diff --git a/package-lock.json b/package-lock.json index da84547558..f3b363bbbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,6 +93,7 @@ "knip": "^5.44.4", "lint-staged": "^15.2.11", "mkdirp": "^3.0.1", + "nock": "^14.0.4", "npm-run-all": "^4.1.5", "prettier": "^3.4.2", "rimraf": "^6.0.1", @@ -6673,6 +6674,24 @@ "zod": "^3.24.1" } }, + "node_modules/@mswjs/interceptors": { + "version": "0.38.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.38.6.tgz", + "integrity": "sha512-qFlpmObPqeUs4u3oFYv/OM/xyX+pNa5TRAjqjvMhbGYlyMhzSrE5UfncL2rUcEeVfD9Gebgff73hPwqcOwJQNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@noble/ciphers": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", @@ -6750,6 +6769,31 @@ "node": ">= 8" } }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -14204,6 +14248,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -15525,6 +15576,13 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -16763,6 +16821,21 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/nock": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.4.tgz", + "integrity": "sha512-86fh+gIKH8H02+y0/HKAOZZXn6OwgzXvl6JYwfjvKkoKxUWz54wIIDU/+w24xzMvk/R8pNVXOrvTubyl+Ml6cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mswjs/interceptors": "^0.38.5", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">=18.20.0 <20 || >=20.12.1" + } + }, "node_modules/node-abi": { "version": "3.74.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", @@ -17428,6 +17501,13 @@ "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", "dev": true }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" + }, "node_modules/p-filter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", @@ -18120,6 +18200,16 @@ "node": ">= 6" } }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -19380,6 +19470,13 @@ "bare-events": "^2.2.0" } }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", diff --git a/package.json b/package.json index 27a0a10b02..ff6b212a39 100644 --- a/package.json +++ b/package.json @@ -485,6 +485,7 @@ "knip": "^5.44.4", "lint-staged": "^15.2.11", "mkdirp": "^3.0.1", + "nock": "^14.0.4", "npm-run-all": "^4.1.5", "prettier": "^3.4.2", "rimraf": "^6.0.1", diff --git a/src/api/providers/__tests__/openai.test.ts b/src/api/providers/__tests__/openai.test.ts index 950b216541..5d8c92f80b 100644 --- a/src/api/providers/__tests__/openai.test.ts +++ b/src/api/providers/__tests__/openai.test.ts @@ -1,7 +1,6 @@ import { OpenAiHandler } from "../openai" import { ApiHandlerOptions } from "../../../shared/api" import { Anthropic } from "@anthropic-ai/sdk" -import { DEEP_SEEK_DEFAULT_TEMPERATURE } from "../constants" // Mock OpenAI client const mockCreate = jest.fn() diff --git a/src/api/providers/__tests__/openrouter.test.ts b/src/api/providers/__tests__/openrouter.test.ts index d592e6c968..91de2739f5 100644 --- a/src/api/providers/__tests__/openrouter.test.ts +++ b/src/api/providers/__tests__/openrouter.test.ts @@ -55,7 +55,6 @@ describe("OpenRouterHandler", () => { info: mockOptions.openRouterModelInfo, maxTokens: 1000, reasoning: undefined, - supportsPromptCache: false, temperature: 0, thinking: undefined, topP: undefined, diff --git a/src/api/providers/constants.ts b/src/api/providers/constants.ts index bda1706728..4d6c4672e5 100644 --- a/src/api/providers/constants.ts +++ b/src/api/providers/constants.ts @@ -6,7 +6,3 @@ export const DEFAULT_HEADERS = { export const ANTHROPIC_DEFAULT_MAX_TOKENS = 8192 export const DEEP_SEEK_DEFAULT_TEMPERATURE = 0.6 - -export const AZURE_AI_INFERENCE_PATH = "/models/chat/completions" - -export const REASONING_MODELS = new Set(["x-ai/grok-3-mini-beta", "grok-3-mini-beta", "grok-3-mini-fast-beta"]) diff --git a/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json b/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json new file mode 100644 index 0000000000..35577ac0fe --- /dev/null +++ b/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json @@ -0,0 +1,25 @@ +[ + { + "scope": "https://openrouter.ai:443", + "method": "GET", + "path": "/api/v1/models", + "body": "", + "status": 200, + "response": [ + "038a3f8c484dea01d0081d3ee77d95aafd9fae5d7849aac540480ce28fa4256bb52665456fd22bb9093480fe1accc0d30d06fb051fae3fa5fbc5fefffbd3de30963d7187584d8a729f7b4ef1a878864254980ac9762159b3563cf373eed5b346923d2bb243f2a021304c9da9a02054d4b4f684e843d1a44e5319825065a5222cbaf46554c68c7edc1e8a9586b49c023a3197f9eb6cde0890998a6968d66c5fb9e901512400dafe1efc25aa51315afcfa25e23a5a443d57c18b6ff4ac4736b598902d9a4014c591c39ea2459423fce12d60b3bc868b07b8cfe0a40944a7511ccdb37c6daaa345362b27d97999a5691cd533e0ffb40665efa245b4595e9b8b07739f010b200c5ed4ccbf3c4b35cc70fd4e700abe810ba2e181e8d5dc6750845a730d554e95807c20b0bc0625ec413d703f04bfa30f2dd2fb9aecb7afff2d30edc462bc234722e01d8c963bc11e616b7df54a35a81fb812a8b9eb770bb90e5dc5ae055601c186f40843f00d5b4a6035b255f00ee651afc36afa790d14efd8b5d04cff4f0395bd8b8115d829b5019504b22c7d056d8d2056dd898fa31d4d010f6f1fa14645216db8625731495fbbf0d50487d61ea11a032ad5d0f67cd54afc76b4419dd7a0e5d6f5e414a40fd9041e45f2d54020457602a2c1bb36b4f9182a5f3fee4557c3344deb36e2ed8e5d0b150e0ddfef6192584cf1e8a4378d5d0b1abf11f00d0cc1f7838aa4ef9c40a2812ba51ad8c17d963cbb671715ec09213a484664730d517519f00e3a0c3df4acdc4a752ed892abba1ec3ab045c37951103b8aecaf703292bef08aa80db2c5055575575d65a3b9a0615e5552a323b45c6302cd2800dc17d66b2d96c0aec40fbce053d69e0aaf2b2c136ee947c1a29300543aaee3a2f0958c2576c0938e02dcd680be60b61d29b063c6a3438b50242d31c176b7ce829c0c65f42b907c54a958e81fa358905208d872c34d3162d09a310542824315405f683aad9b5d071db19517c2581daf751e1f333561da080a5166d0c3dd55ca18dc107c051bdf3bd1f05ca6ec84b12c5d1a04c3ee84bc9261b8816d9b49897691c05f3b3102dbe44bdafd1b21ea345a47450f3f74a078de288dd30eacb278a98245afcbabf94d11fe3c88f7a5854fd2b39fe4c215a443a876e4a11079f81173d0e142da29a6810a25713b2e8cf713404aed8b5d1e24b1431bba245940e4a4f3f5842a4b2348aa3402525988ff4738f2d3defddd3f6655a397332aa18bdc423bc59fee738523fbca45c87162dbe086c4a8f879750782f83b7ac440b375a1b472c2fbdaf49c75789160d5aa13fc7d140e1259c435e2cf7acdf69ff738cdc1f60eb7d6be9aca59e1d9b3c999821788375d7a0bd490b934f40dcbbfa426a0157eb79204f26701b3cdcfe71e1f8ae96e77999a753d7f7d32cd065a0e072a2a8647c63b4238301a70984786a40afd6234eba2a62914ebe0898d6291593536eb8d25b55dfdeaf9bc0b7afffa71dbb5776edb7afff0f5a0572b8b5805e0f85c28f436901c940f063dba510434960cfdac17f966a280434ae8e016873e31b46074260270d13395a4b00e1360aa81f8c320524036cb70e9620cc9955f941341c44cd60b12218bcb0726a8240af8360bd59067208b5fdfd30b61e431d43a0c652a5ec5a20ad75d004921ac3236a206948a1ab61f2c0960e682fbbca0a7fd9d2723e994dd7de773a3442bd6765bbe2e2a8614b304031b0717422bd48a0fbc5499aa6699a2903c9804100ef8e3183822b2a49d34936050406bb75545875f41208eb40c4e9541dad0f9d997d602524e13191e47876a6934931597fddb41bebfeacb5bdf99c9922dfd2bf6f8ec7ef9f2e360bb85a6fe0970c8a7cb5dbd5f23c2fb372bedcd57a637ec94c91af4c5a66e5b5c6699dc8d12282735ead37a63445be8a61cbbdaed9f80035d18012a56863b0be7d4251bcb526b3781e22a2340f0724f8566b588693001d945c1d00dd24d6b8223d611a9dfbf6f5dfcaf9e9437935765b0e5dcd26ae3520873d0b81be79263d6ffdf6f5df58a90b09280efa07441830a234005bd11bdf0f184829b47eca16850441487a5c0cbf6430f9f2f5ed11b6de8b0a5b038581824c1a0349384607c1d91e2d190025534c514a376e16a8c074c31a63f716a54160c7c8f76ac12c01661eeb9b86029dcb54bec3a2bec607a84176a1f1a107a5070743e231d40fca3d7f4e23e25178d4aad89253ae60efc36b63fd3e5120e0ec2009b2745e90fad339d931c2cf787f731ac30f0fef6f40bdb750a1b54c778734ecc8b4f60748b3cf1d2934dc8e816c161a1f4018573bbbf13c3981eb4a4b7050cb2a1412286cb98c5d0b359531360d95e2a31a119d3eacba28f0ce50a84cb3fe998a7c369daf2ef8bd76142284ddc62e46589beea090713fcad5d8cbd54b4dcfb349837285ee445bdbee7a276f3a7624641606c6f94ec10fe44cab89c5cd64389643898ea97c4de02eb08a2f77280294accc881e2d4151f63690557e6eef209b3c427b9ab36d675c4b64f418ee56643ac2ddd16e85b5bbdc1e059a3168470102351aa66abf0e72f264a1248640ff44d6166b6310f7aa223e5bb66d9e0e1559d4a3d15f73b86c30060cca0d562a0dd0ca481192d48380388899dc64762d767b153c030b86ab87abdb47537a86284e80f20f85498bbcb43855a9ffd196ee6d674a9e9842ed3874bb82e534d058946e9bdc6a3ab5b716a5dbbeae59399dcea80b721eed0f9bbdf63ebc763e887a77c4c041e006da4cc69424a8205a65861d3c47a9fe5bf11c195566043aad29ab2ef4d558bdf1b37b76375e69511265d83b47c453590eec40f7de4b989505d01232d3b2de199e426e2fa3d72646c3bb3811097792722d8d95a51dbdaafb32f8de11a0d75f29ef2881eb068e7eac403ecc33f6a872183be0c46f5cae1dc173b4d82df91c818c4dc387d3189c952194c1b9161d06cb15ab3d02ee3c334d98771228f21990d0b28f1e2a3131360a3839a74e5811efa83b5e3c1c52c5fe42d5792f4747708d4f16aebfb6aa0bea9eda910376d528aeae8edb4e72d4830646f634765516c1acf618833208ef02c61a039dc497e9f1106af031b1b75a9e2398194f2106147035fb5b4fe3bcda11d4be1a7b724ae63ee1934e7590c5d9991fc8053f2a8504f9acf6959c8d4286c8d59c256cd4df9edff478783a681a1f8cb9f7e37c6a2813a6fa31886f9d7fcf499a1d7a9a4eb7ff40e9343bcf93804d6cf38ee42a8a5ba5e4a0034e94e197a39ca60cbf4314933f73f8811cf2992fcd7a4ac76d9708acfc7e20b7bc5e802f61c38ee1fb4fd836c02ecef332cf72fa761d74ba16daba9215ec3d703d28f0ebc70ef0c793b3e0f8a7402a22ab7969e8490a84b237ba3b6e3bcee5e81d708a6cd8a64ab5c5d04fa3199dde14e7de287624aca741d1182a2f6a6a4353af3e4dca37a7ec656444d019ae2fc4df081c0de3b93227607e88c7111ebab651f239ed6c6147ae2e0f81f1f63a4d7593ddab0cef08da5832dff27a730927e7e7c9e477822cbe3d6ae7dd6900bb1e7ebc3496ba177b03a88b946d84bcecf96aaa48c407f08550fbd0d5d0e015bd4005525875668457f85d27fb9e9cabba3077fc9e60c91eada500c29f291e45c3e8d0f19655e8b4329acad9c1c3e3e5c63361577fc1e9d2fef0e1849236896183da7d60518c61b3d93c9dc6322a23a09ad5f99d65815f302d688fb0276b8d8cacb4015e1e03b55fc5302a48450e037b8196cf44b66d36f111fc4b9e7431550576c30f4be0b143f72abfc5685181f862b92f2171f60a25f0ed78f07310fc30816534bc42075587ece24987c47ead51c88dc394669ab73bf2be428ea441dd3d3b76be9ec3e2f1dbd77f6b4f4c8e1d34e4a5069674d04147257f8d9763e19687f26a7b71e8f09664d9eab928cb785ea60155f9ebc8e672e5831d763e9bb87559e449e87f907dc4713c721a46a01fad80f7510a503f70514ee87b9b2fd015aa940a7ecc4d8207154db9df5368466bd64981c286018a936b910a2038daa307a9c687e0dc8f23f2092a92e6181ba08ca00ad67bd18a07425b50e1040f15738516f6a1f9a31b9c0af6b27766d7976018324f42ec38824189b434756158b4f102fb51c72bc58de0f0843a85053629a583b368ab6998911ce62401b95b39ac7e7eff0e982b317627d2e0fe9b218107521807e828d002623396b785678aaa3f3fd83b69ae493e46f0f16b319b7efc94c83f28001a5314865588c09e9ff4bcfc81d6b0e8fb28f1d09ed2b1a0413ebbf075dce5c65aecb1480a334b39ef791e3a1684e5f5027ebf793ee4b0b6d823144901b3740524f8896793723e110625e90eb2564584cbfaf81fd00f55876ab0a1e348ebe804e2e8e65cc9f21abc830d296a4b308cbe19a5ccca5cc7cd10de2286e20d1af4f16792de297a7da4d65d06cd36e74a7c3d6e8f02172e2210544bc9e011f1115d1ea16528e9f900be51f80dee58a81e6f58bcf4c3db47bb9dbdb87daf1d0f84d6f358eacd0662811a1e3a0c7475fb48f9136b0fd5b16f891243830f0bded260f1881d9678b7a320e19689ef4cea61c793acfe6e4a60b76a1c7bc7198465a53b90256532c23ed9dd3cc2353b0570aa10766eceaf7ad9023e08b58241999062d7ca9664196c99a52bf965ca1202033233675594579fe814aff3feda616aaa73b1555bb1f79650b3f487256c1e618519ec79b9fef9972564696a692fe01e5fc71a3d79094296cfdf8da5e0dcd4b631eb746dc01ed27baf9d3dfa64911cd5c2b941e9dc7bf7ddb55baf37b3bdece16a8dae2dee41a101ef838e942e48cd478a4505eca9e07b8f04751996d06362701eaa6c942c038b2ec9e5eaea52829865b8315f043ab05a8a52b01c5775a871faf14820d7e45efe386239e90fcbb3cb1baf6344012309ee9387f5d5753330226fbb22e2d3dcb9f676af9af8303fedc99d7dda93cb9389a97c4dc1ccb66616ab6cbaf46e4f6e0177777e0cbc791598ade0dae11e662ecaf93cc5369d78a8693633e30d4cb369b602fbed0497fcc17e597554640ed8ae9dea458f0b221a56c2299907144b156fc7161a3e806ae1aa7223a71d8db19575fa71ed8f1482852279ede9c9293af9c1ddfbdbcb181ef67cb57e8ae17ef370e3431fb7f55ddd2da1a28be274039982f7901d5452062610efd1fd33dedf2851f7003a68c0c11b780e79b5bcab19e1a4be1443e5c3308aa749f931289e16ae2906393aed48b9f21668b5293ae8fc8fa1c53d0052509e088f7352bf1d456d2eef9f528c7d26c17388aa670420a6fc45d49e469c6ab17fa9014385989eeab49044b0bb955a836a522f80dfedcaf417825e04ceda9cea73ff22e9dcfc350dd61f7b729ac0bde70a6a84702ded089603561d419ea4b0fda46dc1549df1bb3db988f41f4b0e0ce2c6ad6eb88c106c5ffc1a4ee762da414d9964981ff47cb8d1c6124e329d64c55cb5490f205e65afc6622b1d0f2d29b9dd11a596b65796473c26105a7352e14228d8b4c4d594c9413fcd7184582777cc91879ead75ab76e0619d029afbaac4be4ef48c3486e1a4d99a46798e9349994c7f4795dc06f840811ba6fad4bf239ff25831b9f0c97c9694bf83ebb7973bb4e9774d8f81a045413735895dab926433158e5206d92751a2334a6a6e1a896d463f04b24c6a533f8017e4035568992d9a2fccf8f284c8490c05c99dc04a6e98a12289e1fae232ad96a96eef2571ed70167aa472f68b04026960daa1657c7fec664f55b30647fceaf6f12dd1db9b7efe36d618727cea5399bc55b315d57c313f6330b8239b808ae0238cc65394451b3636df736dc436906b2bd46479574161e59b16f509a88675c7f328c8b81545a7b8953ac64f46a308e88a450d0351b3d5f859502a1f48a09c24d9efca6e1d166b2edaa195188a4932bfd3c29bd12abfe9d05a722df4df3e2fbb40cddf4fc61d2cc554e9fcde33e395552986caec2ab264da85fc926b0a09fcb0c1db636bbd1a00652e28ed8d779c48da26c56ae456ed3f9551938cb30eb68767b8414f45f58e9900ccf5cf09762a6d1d4c4245f4ebd73c9bb6f69f2ad9d3cbe8d079ffe61eeef0e0594ecf336f7d48284079a56beadd76b86f9f6bc67075fbf8edeb3f9749060e9d97809434284a52f05f5e75840309c265141a6c4848a7019f6f2c47a7c02a2126400b75a4151062c7072de987c32ae6a02e7e7ffc3c9d63b3593fc5304993e2aaeeabdbbba5e30dce5fd068558335e17cfadbd77f65064429dc816e42781e7b960230e58f29298374439fc2248184b83a5d2d133b8ab69988a1ff354f4b2f5c0dda6ff3fedf296469d48e02f299b5d4f7f832db92f4c1e53df2cbeb05acdf1f0a8ef6397359e479e8ce0f31f0b22b5a67fadd544b20a69eb24781b5d1f8b5a3e879e36b82abd3b315146219924567d6cb6a47701bbc6fcc2d5b32793f7af2345de5ea6132061882bc00064a6eefc0d56831d82369d886aa7d2115f0b17e6c3b1d545b10d081aeccaa50f97e1865ef6d6829a246308e6a3d4444fbd5425da81c6b6f4c7d56ffe62938bf3fa6323d9f8270fb86e741f85ab155fd6464e92d4db224be8ceeb02f92dbe5d03681ea217839ab7c4dc48d05ca5dcb88b75cb31e9b91b77c58fe3678596073c7add7b8417cae091e1ee76a5b2f319bcf4a6fc9c1d05b6606db305354b881b49a73ac71b304d3236a7a4deab94bee7501a4c790b1f504ac74c15ea2345b56b85bfbfb9e42fc47f204b03fff17ebf6f2ed2358de060cc72577856019f9ecd3fe9329f2adb9ea024d1882d9ad6f6aae65b0bcbc5ec0ddfeaebcf654ee877bd8fd5f7039994ccee7da8fd4ddfeaec6963a37c4dc0ff76687e08c2b7218d97803c52862d54cfd777b7267dd11728e57c204df83144d6bad983e93d538f12ac650a4c1ebb222f9d3f908ee6f377808ed9a584a39f4eae0f4873afa3a94df728235b2249313181d832bdc4d83ed11ce433ac7ae951568462de9fabfba8102d48cd6b723818ec1910bc6d54056a03d535c0a6824bd205621db380a34ed31e94cfbf39af70fe66efdfe7ef91d7807f377e00a67ea6264a824d4609de836639199b6fa22a888e018cc9d013038790350e4ef4e17adab0cc0eb4fd6590bba7a015855004c115bd0c111a5c2470cb489983f6b2ba6062f929823be324485315b770839156c2ce8f07884afa90aeaf0fdcdb3a295c9786ef9df3b33ddbf294bcc83c687f6ac261a2a5eb9acdc0ac45c7065eee42d34e1f86f0a64e54a1b9608b7262ecef3ccfd1744c39be7ec58994701937f5c56e25683aa609504c7b49bde9ae68245d95a73b72767b212d792908fb0f5e7afee6fdf7f1726c6ac4fd6b9a369230db01125a2ddbb9a9db4365520535a027f34e76aa8de1baa9cbd2bdbb9e80435f9f6699a371ab6e61dbdf13595e76781dd244ea301ac8c2c20eb0b93c9736d5b6ff5f994d7b4d3db09cdc2da741f3fc2de7b279d57e4b357eed9ecacc162abe873119382cd3df0ffe2efb867f8b08665b18247955c827df0c4455acecbb46de93beed97c586b670a96db4e677bc5b0e1838e419539f4f2305050c9423632e51f709ea11847e5574e70be354fe6fb2f0db81028908a4667822bed0cec1f868dc9a584b1f73354b4c9f8d1bc9541b32c566659887e4f73a730c8b9679b09fd37c298701eb39b5a8e0e1c7555d921198e91a9c012b37bb3d93c4d9d3553b32bf00ecd05e444fa51560bc35ecb257aaefbe63faccd6cf5dc1bbea2be4753982c5f25b5303b6ee01a51ce043a4c0a0ff65d78192dc32ab0f1de7de0472007f795b34bffbc4596cef2a4ef4fcbf7f61dbcc8361d44cc7330c8676df0af86837c8cd992e254d73bd4760bc1bf425184f05737b1b345b3e4659a0dc0d63d9d2010c5946551ce621b15da5b4e0372a9cc7803f9835074bbd1c9de1fcbbaf62fb192fc553f2d24b99d02a7a74112eaa01e625db952c9ef190f1e22b3e03977abbdfbf6f5bff3d0a0d1658577546c55ce34195ff80cf12eedb03b2bfd34a253d6c98ef617e5bd920d04e5384320cacb8f9f3f5b62f001230c4bdbb88ddd86804e060ce45454bebb06ac48e098b9e7e4ada5042ea8c1d12a04914c9794a6172bc3e07d461066c4219df031ebd9bd802f2092dcd8029ea38edbee39823f7f741bf1d0a2230e94855b4cf71e0ecb6b20571f0e37a5ce2c8d4a767584e34e89e0620bf04c886f95863dd964e8eb72900f7e54d2855b966efc1c221a4fefd15985f435287a13dcf78e153ac0ba868ffb5a7e015f40de9622a617fdf9630ceaff893c9285b1fe95889d28619dc0b383b44d941739e357c1bf465f9e92e2778a74826909e12c09923d2fe9746e8a4c2d16b5ac04cbe96187e57502d7fa87db347160b3e81826225599264228cb3b0cecdd352a32cd502676b84963f4dd4bc6bec7c09f6968f95b2f425ecbb0727462d2146007977be13d530c1da1d5aec2403158ac4e412007e3c2e8d2fc8b926c903e10a70f7c3d57144295abccfacd2afc18ba593f99dbe015ae13b032633430a38c157bf7534c131c1615df2f8393245f7efa675f4add8e6bc6b37ac03da24832e3a8f71abc330e9d37f36da675f79b0fd717d7cb850c2393c1cdfd50003f4498af12afbb98e5c57c5644eb57f0889b87de44ab042c5b125466cf154ed6ebcda93d2627328ed990e21fe41c2d999993825d06690ec59eac2122fbd6c79a8626b4cc10281c84dd553038b6bd8bac6204f7c3c9fdf28ad1d6afde5b63a658079412e41cfbb768d14534ca038d79a625d531868683167d244a2b1cc13bf58020ec5acb41f900c69e826903d604f78f3fc1d5ed139ca4acaf345b8aacaa9cfec555411c6ecd362849d637e31bfe704de2c2262630c61aae033e76b350863159ef3eba4790493cfbc13a4ee911b41b59f8a9046e89b46b8010c1af4f822dc13d9d948e5f2fb7e88f065dab7563dbb26b1bac28a9fcd9266d567dedcb46b5c693d580269f142bb3cb7e734a03a139d6fedb62d0d566146cc98467f24ea1f8ddd5fb4033bc9f685326da79cce95cd0f50405a44f876bcaf3bf4f50dce28771a000e5f9f7d7293b2fcfcb2728828757a1fe2605ae24c45f6bf2b2d930083a86434de002351d0238a813d843ff7a08373406b4d08227845374da0d4e6e960fa7cade46b15f165978a3b024f88669a55cc80ec8aa07a8f7e128fc87f8c14f8c1ee5ea87100b8a9662877a4b1878d658c055f90be6afb986f5f93dc551c650b736a9f5eaf669f24a43df7f91c0f7799a02a08edbc2715d57f17f6c220f81c410f8324dd2c979a2ed6d5fffa60615b54cc825a5e06682bfba6feadf1365a64c27ffab0b853211390740928282f645f5b111e16310b71a429f11ddd440816210f7070a6b40c44e4ae937e979a4149f86315a39aeab1236f655e8e0d43f1a12460ea283f90103ff27264b5370be2620fca9b9d6976edad96b774f8ae603060d6f63697adc51e0eab5e2972545eccb94b0b96102ac7bfd8bf93c9be7b9f50075190faee424cbe797a7de79503873733eab10e7e491f24c95db95a0a3574d5f357c389de064e32f4fadd190c5eecdf239dcee187435649c3a235c701510576a7cd863a8614011382939a63328dad35a189a5070ab382988a1ee436530aa03f029c28d89ee030d1695aa9877d491e5d854439adbe992c07bc71c6791d4ccc465e143514e318052f04296951261a58b674a88dcea30885fbe1e55745716e984a62ba63aca46b027eb9d1b21c640ccdbb819052585c60770dc2e557665e7d4118969c2843e6c0b6d993466b608b4ca83cd4018cb48fdfa9d0c6c48d1b46c34c25b3eb99d0db06be12f790e1a5e402804259d44bd73ab517dd3003b588eed280a799a9762d6afda3b580e812d4c62c8d37ca26ee51d43ba57b6c1fa153a5699760d6c0b14626135006d8f0f15a3cd8998f01fa9120e09743ddb2107e45aadd9b15476b2b201cdafc364fa81ff19c5d07d4dddd87ec2585e645b09c04784dd3f280dda3f8e591fc1cdfcdb10f30f259b4565e811b546f83d9acecb0f6838ba6900fdd4a5f2a386e2a7f850f9517f3c4f93ec9ceeedfa2f9c427ab228da5537b2fb4413b4a3650bf550d1f8ac236975665d3ec6ce1706be812c3da792b9d185707802384167b2e1b2e1d800b0baf16955bea65340aebf68ef23b04a3dba74383b2a10ef827881ee3e0a0964d339857b0482ea8b11b5626261822c854e855e813a126ae39803fea54cc10ee01dadfa3602265c69622a64c13d518247e5bfd228deba1c563acea0bd4f08fb8ba3c468520b26b141a2024830d730bd06ed9194b252990a872eac34cfa061d811b46284d421f67e8f11b5e99336cda2e8d80342056574f47040cbab0c475775644f46b91c7b68a8a826f8837992e541f21b4cb23c4dd3383200f8ff0340ee7d9bd5d76fcd9ef09e6424f900b227b999811c40678ff47c94ed0234c82ab7244318fffff7eae714968a413ea06183b20203d83e05bc273d20d95a2b2a292e291ea7f97b4a3de7befb9aacef259764b9a455cfa4d93fe9ac1716065a8303700897ac699d253028302ae28a3ac487c14ee3380649e9cec337b0abf126f511a1b6f412f75de3faa0515739fbe187623eab1ce42a4ac2ef8ecec923fa3642c6e3bff5a5eb7a4cf73d2bdcafbb3da36f23acd66da5fb7f28f4af73e795ce952e6cf2775f3e2b1cb0416e6e69590d7a9e41130fb66379d83af4a6aadb1bdf8c65be66032bf6c740f636714e43c77af292d1d3b5f37142f9b7daa0e3a0c5a0622ca602a058047b051318dd8695f253516395807fa943b8259f66e6cfd058717dce040113a5ae4c8a2ab40877903d41046e74b7988d2b525043bd5d1ed10460d869a91595fc3121c1d1cfcbb5d5e61650e130f4c3e00562840aaf8e3cbd7d6b40d1eaac955ccdd581a764d74a84fd507cb66dbf77d61346999256b781f88bc8c50833fca77be803f7c152c27085c5dbb23282b1722936cee8b7787e5dbe731322f9a59dfd10a4e80f7ddb6db417ad1c0e8e8c2fd9dfb196241b695b55c9bd056ca202b233655904f4112d2f8bb8953354385e8dfd3b8ca97e7861e4c53774cc660e03e23e9d8d29a09bec8dfbd3033a39434c49d7fffbe806d637391166b7e6eeec2257ca34c1b97b910719e6a80d798e01f3738cbdbcd0d438bf2835b1ca5d3f7011f955ae5d17ba5a70d40850db0a278dfec00d771dfb483ee67f84dbfa95728f4d9e192a4419ca0509a1bb3bc233b5101d6e695be2a029dcaad9ade774ecb80d01d49484e75ceb38506d9325c6d2247e333beab65f0ecedaed0438be48c436177b135b23b6c45ea56b02e76e096c0c7566f74461e43f2c70cd3cbfe41482a4059036311cff5a3b30f6140368610d811c5c32425a4e457a5692d0c5d40bd70534d12d09a0abe5ecd7e3d473578247fa68a9361f7662037a0c71b9dd5fbc2d59ca055ca78ff15403dfb2ac0da386fd865c217fc095ed03ed950803eb5db32f0f86114c6f83e1a639c0cd4001181e871e4727708d3ef0290197196eea2a2fc45bad2587c8f721e7aeb880df7ae9a633128bea495fd7c94b5f753669b0ee9c73e90ea15a03699ecf6edae8fbf091233fc7c43acf3653a34c45bc614142bb186caa85cef8761dc7e4aed011fa7899bb30a25d7f60e3ec7a5204c1d34c061589f4b9497789d862a81c010ac8171822ed0747cd4d6cccf2665e2161e18f55530d2df031b927dfef9c1f7b45123ac9c757b1bc1765d14306672fef6bd1a7601714dbd44536dbc520b94de6eac7b71974f68b122069ea0b60f2d58d454242e394a1e5b2ea2e62648fc922ec8044463c083851747149848d00461dddc0351b190592713e9a2fcd3e6feb9f27d629bf8e2627e637a7396292e77cfc07476cae600a642094e88c3d21ff10d19b59d13557c5a6d6eaab6af39f98675aa66b7f64f646ce20f15bbb5b4cc10c6b2bb8eebcb09e57a5d66992f53cd3f2615ceb0b8ddfb7ec8e68b951c4da9b6a1a3b500f98411ac4e6bf29d632c8339d03f1a5de5ca978ae087ca6c021d107eb5f881b2ceeef10eb43d06193a220424210cc2341b313040f799376b4866829025ea8a1a11867d3263cde9348ddd7057efd7a10c10eb0122f36f17aae0a58ef56bf5d0198b6ec967c1166278728e5e61a3272ab7d6c92bac4b460668d46ae16e5eac9d410f0092dd17c82c2793001ce52eb042dcf6e7f95071e704cef575bbcd9821d7d1c9c5209239ce947f8163a4a476ed9f1e1da271d9064f0ce23c167221cd43d47d7b28af6872c862f7bce381c2658c78929b4c9743e55c6a8fd4798e979f165fa87917d4d7f7093e2226b2f083d4b5ad0919b1f2377f8a9faf1f053f5e3aba9a7caf5aa14ff3dd72b799f4d95c5cb1d9f0e8285c711171afaa2456be272c6ae1a0b3174e4788498fd65d4b131357273cc68d738949822639c4e40df1ea46663c7422b40b322354c3deae5ec0c465a9737a9081589a62cdbdf48668690cd0cdf1f4bdaa124ba6c438616bb478f7c59cac914937441494c33a0e5c25bfb7458add651c01bce19a638b94f8d919cf564c81661f37565b327fbd93780a4ffc3a19d74ec3a96d35ab625e483857380fe7f226b761dc3f416ee6b57ce562637053911dd15c6898967babc5f3705eb9d79160e4b98c3ab68c2d661b6ef39c06299bd28be2770494c62ebfe6ff66bcd0210b0256bfbf2b64414598cdc55561be3934b647a75b5471ba49e1c7444815eded48debe8dbf9e5c08554a57e706bd867ebd4141fa310b8c9840c33f81fecc0edf7d6b780eee118d49cde2df3f63cb8cf2305ea84eb37ec446e7d14f671f2f9fed655b5cfa773aaf694d733daabb9c259837a3ece6045187cb06e196bd10d81276678f54df49e075aa60da81d1f28f94c5f1e9eae953d393c9a6db5e3c31896ded9e7f5a48c6be3c32dbe759c9842cd333dd54535b6c9f46a3e727a2bef15c0259f39a2f74f4e6f1f933149e99644fd877a9ff493a4e2c1c1dd6af9f682980ce7ee8db3bd3cdb24fbef7f9aec3135475dc83cafc680a866f60b3ab052b3a739521d67d7b1ee2ee22400ea7b1fc021b3c1c01ec45389e6413799a168105280ccacc0f3d4b28d57a883802b30fb73be43689fe853e434c93b335838a7f1a7132116b7643dbce7923fdc23198d1ef9a526e203c4576de7a6ba886d4e277a3da33806958c7aa9308d321900edbbaf73c13b5a4c24b40f4114403aa4e53b36659af626ce15eeb35866e440054b8d18cc57958b0f5a1cc97821ace989ffa3ba3fbe4b7d4dd4a26f4866e6fec093c1ca8421caa94aa8f6ed1dfea46ee0db52ee169b2d4c0d57eab9736594aa90c9dc9d819de9f3ced66ae7e8adf3e28124399c76a5919b75e04bcc6cdca6a5784aac97401477f8abae105e4903a37b3f76d490144f9019c3665ed8aeb85a34935d21988c56aa701cf68144db60f1bb89def60341e917e43db097d798935fdc892d26ce4d7e8bca2af95d2e361dad870bd5ef792a82384a7def2e1de330468dde48bd869ec4dadcf9d8a29bc3787de41d0762f2164d4538727de76c4a985ffaa0a534a1f5045cb71350d250aa0507534b0e35e36012273dde676f9be74aa65eccce2fe9ec8fe78cdd92d03a0e2c812a31c5663bdae143b6b90da45f36d1434d959a2d2a3f4a1c053641b7e1f31e203ccf5c7a9d3de1e1984516566554f7bf1e3358a6b98d94b20e79d6be5e8c6924fbb1266235d58245a416674a9ca777a68f54de84cbb25584b8bc109649ce2aecb22718fdb0b393f92f21273e4031fa111f2bc8db8122bcf95374516215051e06e1066b4ec10e29fa3ceff97e210f3bc26e1d0fea1e59fd8fe0446818c4eef987baf9eebf7b095bde2d7adcbabc2f1947e9f4ca1983cde01a5cd2ce5fa0dc4edfe131f9b1aad089f5df33368b81677511436bd80cf4eaef75cfcdc7fb42c086d05d92eb2def0b01ebddffbe4aa9c9de0f30ae09d0d275977ffb2b0f013aaeada32852d169bc6bede66019e368beda4e21996618c5ba51374ec936c43160c3a31a4a19b496aa0c18de8d5ec699d01fd9bf98c065101233d26a5e3eb9b9ec7bf34467c5b1de8cea541bef69c5e3d158375da5db02d4e40686f15b5038131c1cd728de0051a7db51b42dc528f61afa1674bdf9777ac4f3651e3b251de9e40185610374e19a9ad71a5c51093ac1dca78dd8af4ab1d522d94c10abffea027ee140e8052c02d6b611f0612979ecfe7f390b5a8f00229c84ec44d1cf0ffccb9d3e574e3ff2c785bcebb2834dc7a1ce2cff40237c559edd84b4fc77fa7cb2e979a82150cfab28be5fbfe16ec5b3b45affdcfd58ad9f0847058b0205df44a353a7fe4d91d7bf640c9f3bf687ab85778bfe421e56cbbb8797ed032c9e360f0feb8797ddaf4bacdf5867a5d45addcabb23a649edb89e7468fde4e1f2a5febca0aba2e07e77df4960e7d33fe7033673bf4728221dd057af863434a1e4097c5b790b0c79efc42a089bc04588ce6de6c6a8796753e8b11e069547fa8256aad786b4845d869ea41eb4181350a186a7b033b95be6c76b323fbe6ecc2c9fcff2595f7eace88282bfe747871de3901979f96c1c602997516884fd393e80c984fe0f767182e7f5d8467c4a463272f85e6dd479c3797ae343a63ce16e0fd4f0c1dbd5d91be82bc50bcc529e97e02deb9d10de08113b77e82cff688a9b34f894f5d895e62b557652cce0f8861276b17eb1e4d44d88242fab467c04968b006bfc8bda9678bd7ea84d60492fcde0c4ae360e43eb21daf6394945f114aa44fc28ebd537f1f1853e145acf8e69785d7249828a679d16415f6346734dd1a6a60c2bf30813f3f26fadcdac6bb8e4850c63348c9f1b1afb7f3efe836fc34770e64c8e9041856b44213cb578f5f22d50b929ce6d66a698967c28f601ee2f00a19a95b7b2a26647d1568c054d5bd4bf32f700738751141fa4d7c238e0b4dc503a5d836efae257126117864047f1ad4d43d402c7d63fdf5f7c112d3f4b032b00478150f311e17441246892f2f9b494ca75f659c7f7d331587a1bf731631c141e020bf8b95f42746bee7fe3e9602203d7f338d04d2c32ed4590a95ff3b42dba40108c5cd72abcd387d09e301d29388a71f2e342e174cd4c27efffe7a160aa5af982a698e972aecc861e939b03bf90b39e3048a9329fbef9cf2f1fb097034da0f44d563e230f1753b3bd5f62185eee53a5ce2b0ca20e3a198ad03fb1b5414719ac141683718a5e86514bd3143d21562f855555f48f8f3d513bf41146ffd44aa9afb17033a73c51c35e24e07b4cb70701f861bfe1627327e0999cc3ed050f0256d8d5d8ba7d2bebf5ea9b2bac128d0ce90d2113b0ffce6816447b2147ae2d402eb0defc7bfa3ef097ed3091bb42aea2faa69dcd77b0995cb23906a29144f9396720553a43666041488e56d7ea2b5ae8ced0b20f0c6700c982f2ff0546f02926373d2590c12a522206c0fbb92b506f88886f0c292cb8cc46d69f38eaf4827c13af9d73b172127d4452422f97264caa5d435a895b2ccd33ac1f31b48f4aebfb40e3a7bd40e1f4e4f9023d66449b9afcdfbbdb45654bd7e73181165a1a0d32f73f6474352dfdb8d9559cc69deb43b493ff9648624520b51fce14e15aeee4cd6e5a7a93adbc8deb94671a4c318fbd6693cfe679c4a3f8b683150f434fbdd368e7b3d09def0523532a3d16284017b2fe00a6683da0d2ff5c00dc70ac844ff92201884034201031e012ce70680567bb865eda8290799fce269602a19f70ff914c5252f5bfc2bf938781d3a9e83e193cfc186cdf73cb4ea3a7a05cd56676eae9d4ac9134e0efe75b2001337521486c26b054cc7248bdd763f19040758c69485644de4f8e027690e75a9140f7ebfa4047f21119431abd75673016a32edff43cb1e7a0c4e5777e3f21ff90092e4022cd47b48a186d29b6a61433f3880efb32efe1d9d98395880522fbff9429a5e6a60a524d6e02b572a8ab72d8bf9d0c7ac2eedaf5b6918e90b37384f4f526c0029b0cbe3bb751d3a93104afee014cc6d9515ea16acc15898fe3bc901171f1b7dc714b8f1c1a8af28e77b157a2d7706a22b0f0bc88564a28a558e3edd0375b10f2092072289b5f0b6c774f57b028c85b4796af4b0cbf5befb8a5fd2b26545ca19edea028607f2aa1699db7f44379955096d87d794f9aede13939667060d5644654e4a4c72abcf19d56da404a370d9ae842e99750318e694145bd8a098864b08d27a4eae8c47a03b6f25aeec71dc9cb723dbf9889ccf8913111b9781a9c9bb83ccba570f4af1a50062da74af7d0afb14d446e7b1a9cbb81559ee5f070e373c346c35439261f4b55d30a4a622dcf7279e7dbc88d965315ad9ef6f44594e3ae2af9e3f6dfbcc78e5a6d2abaefa91ae694861b0d8232d0c33625e0393228d74de20a6a898720f97284ed6a39581b7f71344db304652b6588217b83d2b5d441f1b783da406c0546354ea208b67b38120c52cedb5f5e37e6e7c352c760e5f8646fce20f7c572f021ba837f2c6e9ba87170dfbd8cc4b3a9c022d25dbb1dc3e7a24b63b8210410337d89264c9f7dbed8c9a127b2b63d7b723edb03ebb1f730771054950d7a761be230f79f14e6bcef72932a0c81d9bb13c99838b196b6df810a4851a27a5d3a841cb4bb70413daff2b2dcac93dc95f353a462218b4a1adfe0e9f204948fc2bc8d624e0830af7b775a80e39672e36e4f47d1e4c010317b751199aea12a47dd150ea125841604488c05aa544d08834e245784d200f83f71be934c73b43f645fd046f09c5647c30c1e71b3f478981be8b7189c4705f40c9e72a83e5a71fbebe8e37b49913bfee6bcc528aa3a34f9c3ebbf5427deea9263b91f5c91317765c56ba5ca522b915cd4a00a44a855b4f99c60f5169cad0cba4ff85c2f3a24cdf2f772f9bda22969611c1745a6a2d9fa3d7a4c3cec3b1838ae13291ef5c54015c3a3bababb1f83d6e8c96fd8d5287556616698e9e2272f9646dfc0cfd8d5083aab607593e054b18316c9b0b6581a7d6fdc138f118ee4a03de60b1eaf75b0ed861279d920172e748bf507d826116d57f5d810ac975adb466bec6adc33447db7ab40232957718e41a06cf99356164ba341eb32828b329b9af47a83dac7d6f4f591292b3109fb8d4525ad74df689cd57101a5a3496cdd64e517ca3274225a343b5a3db28e54ae8668c4a1b7f6f3f6f5c54e60c82a429f9bbf78263d12611e49cf61ea3b32cae74889e66b8ddc186f8a22f9a187864b8a2564dd1a41a47ec4d2a799da55096d63f7908c435ab75d981a57e6eed02d02b63dfaffd27d0cb883666799cb02ae81cbd727e07e48cd51c02560328d9b7f21d0b7f04c75a04ba724cac9e80c4e5e415fb11a659e22036a73b7cbe592a135ba2993194b5b716000d3048fdf925ca6f9cd916570753ea16501c9e4995d9b0f78ac22df57574f12b26a3c01e4fd06ed2ba7ebacfaed4ab5dc9903d3b36ec1d2ff30286b822c6f68ef5f9a1fecd82866ecd0a7a0f6cadabb31c0a011fd5b2c5e27f0c33848a65ab88578a230353e3c95f6611b1298d480dc8ee21c54e0843e1f35a5de5ad15b6540bf99b24c3d0197e4916110cbb4e04fddbf9bb54891cf4ffac59fa155cc7bad4d2c6d42b3b83fc054224217cb358d3f9a125f1c51c3d43c90d1810a60ae72eff13ed6c8f6ce7c195e34b4768099fe782833fdf161ac48028dc3f821f8c88ab127e189a8bd4cbde82b1db7a00d77fe0e9386bb0e7d2bd1c54feefedfe446e2c199e85b58cc7e1f63362ff2ddb3e85db838b6c67b907c80085a6b21a55496762698b23a95630965ce1ef6d2b7b135b4dcee7d2614e29d74b2afca030a9828a604f458f6ddefa09400a3654310f59e6f0d43d6bd0f9e91cc7b6551deedb8276d5f23975d764d321a3ad8ac353649459b2e4e28e40718d4fb0cd17a8a516e9449f991c2b0fe13a5eeabcb74f91cb34db0f9185c453ccdea62e54e3976cac203696e1655a0b6c2cbe9c8a6db8b6c98886d433e809ee999562a428ff1aa80cabe1ccc260dbf7bee39c0856a88f7b8bff57077c404778686524a7627087e03e798cfdc5788b6418f95fed8eb74ee6aa88cd2c4193a4babd1581d67ff435d1649b639177bae6e644a29a3026066e6023e7e3145463b6a26ffdd4e92e67783cfd6d0899673a2de92e9bc9807eebe789fa26598d01333959f9eff25f34ae7df7ca74027443b0974c24d378ecb33f19b1b3ae1cdee1a27c993f01f63a6cd8ca9f72d1b3ae19d511bcb3c3b223663274194942f440ec5f5071b4d25e251fd071b3ac110670474c2cfdb022d01e4ae685b8e7909a11db1e438fcd96307c08721e44607314d7ab4fc30cdb405c05eb68c36abd7d7311f111ba6c066a29ca763d98468478fea42b1c7c4c84e196ee2c9388257ed99531fa409aab0774b7cd91664989e2dd476d7ec2be093c43e3e20f64e7240125c1d9312331ba3962fbe2c629b7eba054ceab169271143cb7e3b1282939ca786f9f5090ff8ff0340eecd66fde95a8fd9e08d2524cb1bccdf02ddbbd34308b3267f29ec325647961c4986f0f7cb610e87d3f8ffbfd47f791a0121200454440243c3f629603423506c205906b27f29f59c3357d28cac3ceb75bd529a5f2aee0506a010d2eae26150f24beb001514d854644addfd1e94b2121cc743327d5e80f9e3ec0f92fde57f7a9c2da09404808c2a1d7f150ca07b0d056d65b80b526d6da228a2c1402bc395869612b2ba375d5f49c02e13795b04d93e7ab2e46cb4bd264687bb1461917bc1c8c7e563ef61ec920e282dbfff3f7299172a5fe92f8f4ccb0de95206cb894919e73e018f8446430471253ab5e5a45465f9cea64bee1df8fbf4ed2fbfa5abe15cb9c22bbdcdfd92acb1edd27303324edd7a3610a089bc94d687a5feaad2dc5b6e08f3aaf271c068542a9f3bf6d4fa6918c82fd14e471d2235df568afcc8cea01d360e3dbd5ab4bb869bef1152788752e41bf811bdc38e6591a5e9aaea10e16b19cadeaa85472d36a9c537ef7cfe3d96bc1c18aa39bfdc2372f1157faeaec16b8611dc788804b9cbbfb1111d98d8352248b61b4f314940a685d845c43b452b5c61f899d18d5344280a9423c38c28aba186785ca3c185d431e949fa0d2588e8210f685867f56d79eee87cf478cd80aa565d74f9f6015b8af7d546092b63031a333cc2e17d0c632d375cd0875026602085df3f67206950d8c740142e10d1f274adcb4ec862d57c841030cc32fbcdb8d7d493afa6b3a98ca963d90d54b189141296e2fe3d54efc1769be3f8f51b3418759c5a3ae1406179c16b879e7c4ab35e298e586be699e2043ff3fa756f78bbb6869fbe6713ccb9526cda79dcb11c43151519a8b2b5c015d7730a807ae9616ccf64915ad0b02dc4681f23560ce07a1e27877b84b3da377c54d67a7d269b60b1d6043e7952840c31c7964266838d00d58502c844efeb8c6e188df41b67b919b4037042045b3be25b5104dea20fefeb776f58147551f3d924ee042fdf20a09b399ac25feb4149ebd01e3913745a9ce0dc6d3321396fa6b47fdd001113c4334274fe1a675f808da1d1cfb564639ffc51a0436d264f87c4bae7ea6104306f30d373c810b2097b09dc8a1549977619765b618695a12733020366faf8ed0e1d4a52dad071fdba2cb15517f7572b8d0cc2d3b58b47741dc5919d5349a471bfdcdd812a36f063da61ec3b2f6a66e15eb7724e2510b933fb18a9411091b3a5b99010875d1732e3bcfbc256cd7d9cc96990e090335687d1fdcf35a0d24b961520bbe1ed2f6d9267394c78878806c747741c82b329d1c96dc65eb38c8d30cb43da70f2ba67ae61d76bc87217e115d34014f21d4bb52ad20a18efb977bd66aba0e8134c11f2ce8620e7c5461b1c99fe520e29d8ff26f85e4f870c239d9827260254a1098106c5f1c8d165d6022f3d0ae1b8af485aacec9068e95abad3d46627ac126bd300b7890d1813c45a94908e9c90cac58b9a120e23ebdf1a6167680f1457c9fc68c86bc068bbc4f25fb349a9238158ea8a356ef343aa2735e6a5edec78a237e28e9d9d51308aeb7ee7bca3429dd38f32cf9aa0a4cc1546f5c126cd441d1849a97cf52e4c061b52046ad81cbd2edcd9946cca3cce32d8d4815145a817f7af14670df8da034cb4ae1b7b26941048dc6ddca7096c42b62bd05f90d48394f1eae8040feda12c03d6f3f09f9327de60e13ef10859368554582d1a36f7346d4fec9932a08405b72366e925b2502112b96463ec35b3a43c65cb05c773bfb0169163b2504eecb853072d8898f8cf5316553e7a199fbeffc71dc98f865e74bc2e83b3481d3e88eed9dc2dfbda35dc3b8b1ef6bbb26fd885fbdcb1545229112888c0c9d32ad677de154381f393ce04782799926777bf6773b8278287646f51408acb5ad704be33a771d4cbcfc245272c9d058b2fe0e2e6cc7bf063b0a3277c6addc5d2a52fdbfb4d86b6fd7f83d1bb05bfd3c96ed729d2d11d464f832668e7d4cad101101b2417a604536cd99640f8a6ebe0305f775df3ad3b2cd42d6a55868193f6d0afd296b534c6de1e8dc2feb0f101cde415a8e3e0ebca85203b4b83161e4806c53d05ad86b6b3f8fce824d84a0a686c548e1c969fe11451c43342192de05e7e1fcc2c1f5272998e2aeac7d8390836789732ae01075b8d2c7e2f304cdb2f6ff1079066387376e9afd99b0c57e67e7e7f207a6a091aa12750f4cdc79ef6997023e576b664e8063bd7b6d4a6182017a279f75a37959c6086a02440a54d760d3074d1e0b20bd5ee651c7666c27957de294021633778d3387b8aa18c90c892578f3a068e4144c2f03a9b4617af63050ead7f14a49c7703a3d11462177f33326ff4c3f06b261bb285b8eddfdf128d89e3939bff6d5e118db05f38ea088e21d34cd350f2620a0f2889ea15b114dd373d3236db58d4ed5058c022b027cd93c89d97617fd0096cbf401185306169eac7b36aaed731e6f2f376b29f611774284cff618946176e705dc7505981970106d0114e190d6a412667bc6c32580b6e9684e8c345dce30d661ee2d4d495690650cc002b88b0cee00982d6e4bf4336a995c061c2c34db3b1bbac07307fb8df8bc59291fca5f2b2c5021e2d83f7d618742fa2dd6ee8b06dd94e1122ff777d3e85c8678f2ee05bd8765fbacc46ec2970d5304f12007918f0ff91f2baeb272b77c9f93bdbe2d1b22b0b88e98a216ba79ce8af01a283c6d9766a22d04b8f531862c91598733bd10e850dc8744ad1d747f8325f4a21c4ba3639dc40cb22ad813e1fcd8a5a8898b6202bc4235f0a2ef34226b474a032763a7fb44c6846237859ab43d4b6895cc7aaf0d92b70bba44fe6c03efa011356961347fbe8709251ad81858f28a0b24aee6ab58f8a735ec780dc2eeb614b18699e0f7bd17390b91ce1a8637e67f065a4289d2b87e0d7c3f1f667189c483e7d38588d0b49939284ae33b13f1766b309694b3352b193b8a0ac26013f22d98ab2cd8fcee4a65acadb2dfa037926969294fb3bada45311d4ab4b89fd6aec9fe45d8c2c49aa64d32b7d60f6127e25ef4c75af9eaeca4c516d90dc4c03b6976c0568aaac2864e02b9db31e550d5868303f4b92692b1547e204dc14812fe438887c99d183b6e8afcce7980a4d00830c6d8ed03b4dba601cf38f8ec20434e98c68f81942097a9aa701fd9386305290a948ccf10bcebeaf133828c1e39e02c0067db80d4cd54acb55558c1a2f05c140d0d16c7725b0c9691be37769919d829f271f22e96ab4eb8c7c93f70a8016b1353a18c97d6c516af6196ce606fda24290b73c27ece55f13b4b5bd04640f59befde63094c7c69676209c586c77fc1af71c4b3103b1b029d818a5c356cf31ad25d5e994777fec58a6a2aa646fd0bfbbdcb9909b1b2de975aa2e8394d0242cb66626689be027dfb4662d74ae220064cf0e09dc5dee9232b6e4ba544285892641b42ebc809b252a1b0eed11e5a752731ad7ae3f86b6d0ba8b0dd197238bb29adaca12804d2fe749454ee3e22e7437d0db3d4aad9e065ac0a60543b795b0e9a64a394936fceee9b3c601b0a3f7e885048a88617b885e028e0271a976e9772d1b6226401bf817337bbe3cb7c1e9b3f1242f31ee6f529adf2f1fdbdd28267896fb571267531d2d9783c1e8c2cee45406768283c1394b116ec06471e42828872c929c676fdd37c5ed2b07208b0d53414d1153eeed7617a294ab4a0035b51b70d60dbb51c0d9666591b87434901e3d5e2dbbe95b739cb9728504d3f534eb4bc2337f8781b415b167470a0ae8182cb1c69784823bedd05374f0b8db331d64dd8bd3af19c9c39bfafb9d8e4783e939bc14e45fc273e516110b8ceb1d15f6fd370e4128194fb599621c58bc9acfb8bb73ca6a1d0922805a0e58b7b61a18a96a52768f94c7626dc6566fd150d7d74780e4a229a2fa529c86f22ecf757d2bd329218a11bbf4a3ef642b9ee5bc6fd3215ab891f57dd64d410b841cbdafe9c90f149832533d2056910addf8e4a64028347bf7ba1550b8f50e062a6aa1efad28e54a95a9aecffe6259c235ce369000b5569d98c1f16698dc910066f7fce3153eb929a806a9b9d9dad001b887b428d66299cfcd0db976cfebee3abb9dcd43c421b10c323f897325b4806ce9a6f92619870845bf9327b5743fd4f52de451bc313c3533b751d88ecb38fc44f0c1b5012775b59ecbea8a3ab4add3953e2d81cf537b4a7e49fd47ec422623ead2031a1f817e5ddff629bae3a82cd7d31e67dac6497c3ffae32ca18f68d09b623fcd01aac2777a73b4afa86b226178fb672610dde964c8124f40ce36e553c84b2774ec9abdc66fab94313c43f5f7270fdbb0c973985f81714f70aea22aabe0dce14b494b2e3d95208cee82eb42c3b66ede3bc1308bc04060a827748579ae36b8ddedadedd0bae2cd5415dae63e59242d0cbf37797a31888989a330e7a6602bcb46176cfe4ad0113bda762f96df249f3aa0515f71bde11e6282153d34a5d92b7c363f06c6b80b6c23e8d3907d26f3e4893242e9751473e5dc86137c6ca2410a99bfa113630e5c04038e5c58049ccd5409620770072054625d0eafe1ba333edc1a7c9c763047b6aa4352dc5ad4e60b3e1b85815b4f64154f1d353a448567f0f5aa1e8d991a6d0ffd4ce3a22c498937f8be918783b41f1dae278767fbf9d1414f669c08946b19975a3744aff5e37e6f550f53ef74314995140c62b00e864b1513ed3d6da7a9282a340e7a4f46602868b9f3c153c126e421848006ca12e6652c22484ac20c4b3ef331ec299681ed07da9e5890955bc3f2e56216806471e3148ebe4a0053945679d34abe95ff11b814952aeb84b30754654c8699142977521c091d79e3dd4d15e27ab378c4e8482c2e0b0ff0accb30a148ca455da08e5aeb1813fe1a2217455a1fa2f2974b60c149a8869458e92d3d04e82051035aa63bc3fc7078735834d5fc61fd54aaa81d489eff75bedc3f0ac3b22e79fe187ca2218d547d8cc094d260846ddda839d10044de0a8e9665bfc1c113bf0dd01860982971e5a576851d347b8279c504dbb64504e3bf44d5544a6a62d38b84988be456330c8b94f1854bfb05a28dbd77a36e968dc1a925a678c982b39632ee16370b76d7b0fdfe6d40f112ee7dcb394796a6529c895f8aaf156b3576400663fba8e78c93502a0ebc6b7457f66378528798dc261ae95cd7a7562cb8e2c9870190d060254105f712049557f338ea56e0cfa9ec2959c2cdbcc78e57233636d9104c4874e61a2ffa4fa747f15391711999d957480526d9638f7cdc3ef2a3194637cf628028f949bac9181622364f90f3f3648b25847a19fe73e5570a15af330f328fa9a846667abc978258bbe4248bb26542500611481a3abb51dd96401095cb2c84b115696d0a8766b68aa093cc49c4d2b50e7893029e65a6bcc13593aa0cc304ec50128731224280726943f01eb8dfd22534a6b7b0529963d9910f5073ded3b3ae71d4f680ff065c88ac923a2817b15b446bf347bf6ebf2ad60da32959b0be556bb435824e36b15661bff6a6bf0d08870fd1d73e1ec8746c23fe3cc9a2c79560cbe3f8d53acb347c1146b79ef9c6aded252ce005d7ab0b91ad523c96fc029ae5b0f39bd6e08d34f4ca07d59463892636dcc7b6e699d0900dcec3b722910fccbeb58c40b9738271e52e051df726591f9802acba4e8d6aa796852a0448b1286c83751d349b1bd04d110ef16ded71184a278bb9bfec528c132dc9a984c7aec1f1685aba3a95068c56337a5b74ad8bb91582478e29c75f3cdf7a613a923edd8a577ba24721c26a6534b5925e4c0b629177e9588122420a16db049e930611079765753e3a7876ff384e2f37fa898cee9d0b26643e4b54c423adebce4467aaab4df405d623f3188787d76798d76dd8c3ad371dd377b5692d9b46e3b00d1cbf3792d73e1ab5b3cba5be25cba2cc9b4aa9b415b2cb57aa6d56a29265972fdfea4fe98fcfdbbcc7cb0fa79bb71f0af7ce201fed6911fccc09d155573803736fb598a2f4d1a33503e4724720bfbd97477c8ec3c3ecb9ada5ec62eddcd766b35f579bebf398de97e1e30fe7edf97d26f65f02d506c0837e7482878d7127d84544083ca27afd748c846000716f6a7b620d7f5c332943cad923d3650878b42d66b6a74be4d3bc7d334defa2fa339761399ac563ca19a65ed35bc3fdffb28a869dab552554aaf0b36afca31e1eb1e3de2bcd0cd9226d6e62591cb35827da67b7ad21788dd595d10f2bc11de026684ccaae431210ca73506d278d51bad82b0c9dd1f6b2c9165fb69d9b3868abce8640eb793ad9aa737f18c51828060caccf7c6f5b8d96950ec4a48c9dfbfdffbf259ede38e0a0bd3f3ee62d1abca2c1e1f7ffff966411508029312cb38ad2a759b7b78ed17a82478e87e807a60e56ba9d31f18c204e4a2cf899517604e89eaf8f6770d44bb2ea4cfecfb8644a47d74b17748a7902ede9998497e626f637210a939445c52ac2184f67cf84c8ed8b8665ebccd86babb8605eb293bacf342b1858f3d5b2ebb097648c92305bed5cadb222cd569867784d397ccf666b475a7a71f4659c7df20263af267db837529fe1106dd57e6082702923a4d62a46f25c05301425a84010766cbd13656ccdb6a692b02a341aa3690259adcb5a45ec2c56f7b2245e2a8c0a6d9c6fbb731e14d0e89a3e00f5a5d27d9c5e09f134bce3223a286e6d3e76a8b32e455224f3353ea49ba887b0ff9371a7cd9ae510ca118844133aa43910db79d5b6c7f8767748b4ce52da43cc83acefd0d76faaf6705e4de189cd8031125b1c1184f4cbf29b654ab0a22cf198955da9dab2eb8aa2ccd4aa5ca15ac0b63fae62d16e7efe8e577878ed7503efd0c7cef976433ad42ff57dbb48e0614316deea180920bceca84f213a3fbce47d67dc14e8c3e4af663186485d6cdb1fbc30646f538f535973dd153ad9edfade1b379e1cbae7e95b87ff69f89fb610f44bddd77b879f6493d3fbb7f1f76a7f9486ef93a5c67b8ede2c6637faf06942dfba3798d001e4bef0f0db097debc410775567175249b05bc12ba1c9cbebf0deb791acdac058ab581650a200b9b8fba120ce5411375f52a6390ef78d5f0d8dc5a455233565c7c2674052e47534afebce35d9917e5ddf46ef6ccccf7854be264ad3bfb7b68e0afd00f3e165f812cc7d83d94886933fddbabe2da85345d7934483869202113763d2684ab2aa66a860e7c308277db6ae43b41822834c6fded0658e7e2d380f930dd871d36f76ff29d755465c333ac0d39743606ada3c80b376fa50487bc1194729e19ac6567c10b0a3cba40625b2eeddd65b927f6ab103f7ccd7f4f84ff46d801267439a7645f211241674911d4d7139a9e5e2a76377f89edf0c3bc2777046895ca946dd346716d4efce962981af2b20d3e85233cdd5308d5243b299896000b732904f355c197aff4e045e9691a96a325417649d2587cf031379004ffadf2953ca0b24ac2dba4f0617bb30a9249cef94ba965aa932c5e545afaec1aa15a6d3042c09e7db55ef46c52ba1a990a89c9b915a2d70f1440d32f53dc8d830b21a6c52d6e3156deb33e2f048737e2f9a8576d3b9cae7fbe3c5de1301b69fa760ad68de94774a9f5caec78032f34425359ae0e74a8caaac447aa4bbb5436c43db48aee418af53b5a566414f88702445c6aae366ac7d871354bfc85b07592bee60ce1a3322d1ec2e079e217cc134afd2f1a1ccc8335e079762c5643f2fbe924361174e6e7100d7f33c04b5fa0a8a0a4eb3bcdfc167e781bc773e1424b9f21c5a503ff1191499a2e4844881c18be4f2dd80016304b0497db41b928dd9607cc5c9cbac6eeb0563df44a76ad8ae1c85fb246a41fbbdbbb14f4fa97ed9f6cc2c76965b48247bc3d1572771216c21b73f9f11e6458211f2484ac1551a31a8c3daf215112d71c77654803ed7d6c0e4482888a5cdf750ad5459ca6a4abfa32964de84246b47c3e309b75496523591cbd1ff3a5fcaca10640d3d816251fd43ee9ca8f62543c7527256322501f679e349caa94432b9cd48cc81187abb794a21a3975eb26c66ba82f29a02a4e1c71c3184bfc835e482675c499e7f7378c77221fee75bab15970677620bf61ccd77b006998abc0fcd4db6ac7a48a355ebaa9a7419ece537a133b7ca8484c838f526b32d774e1a610027934cb61d879d6c1d80d19fdab431ab1d0fb9d73416ab91d3e98ab144ab4e5dad2ac98e1bf57225d75a00c0bf7bbfbf31957e37552d55da2b7738e172baecbbdf916ce43cad9841e5a33b0ed132f0c3323e66c3bb97851ddb39ca6295e5c3e65752917afb29175956ef1d9cca422b71f17961e70db50cac0ce9377c5a39b190f472643371b0911e9ac8c6b3c131c98d25192ff5113c93593cbd7bab7107d6205fe48adf91e54411a8cb230921c1c51412b5436592a2f6f05b9518212f536171931a7a2a381df864fc75a4b9f3c794a22ce3dceb9c0459a9209db4ceb45e637c182494dac8476067c3463385c09c1206ec61b2f0631d853cee248ea1648a75fe357717b2df0478ede744e9ec1a3fe6849102e31332a72339dc3ba22a8c5d6278c51502b1c41d827199e270714bd9266701f46453cd49482c69e997d2d56b65f3b9de215c850b00c4c572ea3a7799a781e03360426c9a88246d45573ca3ceb3d8b8b1599910b48af0f92b314612fe21f4aa096cd93df76fb9ccbdb0b6e58e43c37469833c88427dff0f94165575f7a52399f2cb6193b91f15c12eec1ec3f2dfe62417016e9f7aa39dadf16800f8ff0340fed4965fb5ef930b662ca1a7c3c75639c965efc1129a253311468006231149c6902a4df1cbfffb66fdf8b54a7f2161220d3a722ce322ecabaa2f7a402c8939e6d900d7affe3ddd33b3404738ab0e41938b50710651caeed9c339b77151e0121521746c48b3deb5ddcac520e8b087c51b78f7ff3e05d121af0a8506ad5c83a805d26924d280e131f173100f5a714bb8a42d53561c8a29e2b15328560a97c2ab5e1f4ec8205c2c4cb1da4b2d4fb314178f4b2c5db21c3f7c118c7196b229c278e11106652362af04bf05b9331f7e67bd835aafdfa49bea6cd4aa47006a297e3e2b9c91bb741c17042d4e0b22d99780e3c91241f9e8236532c387751487a598d55b9e1d325cad2da0f06611dc221cc31badbaa513f1dd22eb5f6d6252c7596b86c6b9019046ef332b45a4876c2e2dded9b67d973532a54644e86fd330eba3c9e209c2e49e51391372b37ec1edc8d9041cfc4aa3b33a5a5ba533ea40f02ef9cd9ee627cb71fb79d2bb6861e92ee28f8bef903013ae3747f2303c90c7c37581c8bcd8105a9d817569ca532a06e41a8d9d4478354be8f21d392cc0d8df1d28bf0f8693d539309ec2a6bd2f637e0f48198ccbf793e9af5dce3ce36b361116493f043890050bea6a0c4b4ac5cbab52af848b71ddcdfbe6f75917d7c8bb5e3e8d3398cb66ee9577b36e07c9bd0ed11e69606d205f74d81c40d4b49044acf81dc940e51cb2cf256210fd372476aa42a5d608d7e9fa3950d4c23473d8231101a08d2426201ccfb6dc318f22df0ee799b5cb3b5c0d937eed01fc558addc827baf6eba82fefa2e6bffda5e2794a21059324175f896616a6280c37f7341562edb6ba508cf9f8e0d6c2981865696cddcd369e2aece25988e891a437c8993e133c0a1f91427fccc8ef8123113541ceab472a6c11ff2751c69071c846724ad128c6c071531fd6be990e90c5ff1a5f5e1b5955d07532d9ae06e7c954ca564343d8b834a3451b94e8b89f46919f481996f0522a1ae2e3b2dce556e3c964c32d6f9c460cae1c0d86e934b6913139888258bdc67dc935fb89d3dd1aab22abb66754a03db61142123a3fc6093646528af504f39aca7f367c161dbd4b1d4b91b3d1161ad19bc60cd6366c62065bebfef80cd645d3a649bfbf8b0213fddd5596804cd5235b0adc08726f447005f521c50c6c9b2eae940a8449868dfaeafbe40cd465a595d64ab98b8ca9760bef06d4ee9f8f335936ec46b4e9b95b631e3d7733db7d16076160cedc1fc5909d4039334d857ab55d10f4a92df95493acaae947dcba803c9bba64a53309825d3bbe57592bec4de0f78fc48f147ccc7c8bb9a56cdd40032ad23d2261862ec2714867351ac436ec09e81523074b84204ae938a4d1176871afcd7959edb3d1973528cf16a4b3525ab31624ae647f0307a98c23a16e6a7db5f873bc506e9e7889f16c7b693b846c52119ee10c27747b34fed3ba57198ef04be600a9bed61c141b2c1524301cdfd404d8f4a2299c797462b760f6c4c5916e03f3ec8c1ead91acae7772e77dd799319bb56e0f309ed75f66936ce82b367e30c578851bb8ff13c046e8ddc1f9c14581910ae1876a7dc476b77920977c89f4be18f2c86a70b744914d964407a1b040fac39042265e777125845d26e8748b4ede77f7b437d80eb2a873e6d7ee81384ae3648119127bc17d706506ab919bb5bed528eeb8fad5a8f3c36a6423b0e41385f6ebbe00591856ecc21042327602ffe0441b0f1a510be47d739f3735a80996b351e9469c57ecfa1dfc92242ffd1209a12337a79ea91f420b8aa9e7edf9a2d360141e1052f5151e37f78e547ded2078c92a9ba14594630e43fba70d919ee6555b8d53953627ee48d8fea60243a08e2ad2e864c47edcdecb51f3a2af76360188d852e75d57d978a1ae48b38db7d5fb999e3edf2f407a600a859e0e878a7a2dceb8244c111413287d17eab4870f9cfc9001af1a68e9c5ecfeb2e24998a4f5517849abfffd6ab4dec5b7b9bc01c5692184bd1741ab21b7906fbb0259979a6d02eefd8547036314c82c4b71338c6dbcd859bb7919bb75205cb17221e1ba764e5d21ace013e44a4966178aaf3f3afbd358a97ad1fb78532d0b5e310779f0dd57da6fd4f3402a9b339469a006ec617d625a85a7484345bbd8905ad10bee561ed8436371e4428ddfadc45716e9d9f6dae14d53ff18479a74da97da4fb0c08bdea693b92ed74ab404c2fb42ed3632a5a8bf0d9bcd47deeff0985c4e9a7bee4483c29da06d9fb77a07e6776fcf8382c104111293c13a72bca4cc319b79f0588e77b8e1ed8d6a6b398a12c6eb0953e326dc46c76eb449690f1a5d60cf3c3d5dd9c68c14090789dbb54607a62802b7297a01f2b2e21d6c3566c04848aec4e4cd262bf9189225a8f43ae72e4aac64299c07699a20e6608da35bd4bb9d2138c1b22b0527557c0a84b87f836fa20f7153a0dcf57ebfb8395c7c08333c00822285b43ac491ea3876944ae782d39c1c995525a9d007fd7bca2b5cbd295a50e6015250c9e9149b3c290655121ec22b3f93b91d411a3178dcee306a7489edeae45f65b11166dbb63bb03672bd0e799e503e4b942f92a8e40b83f259a2740f34c49640e9e141cf99469b99e415abf4a12a607d324fc9f255e172f5eebaaf39a7f1dc7142627b873db034624cb93d6e3091b5499828fe3c806a7849d12d9df69364c5d6a71629a1f143dad4ce7402b574ad2b1281e39e0a6eaebc6e8301751d4ba41a4d122f1938702a7849ce44c91400be2c552c0a087d02527395756592545211d3517804b5deb51e9cd84ef2a2bd8fc5c8ebfbf1681a5f4e5a968088fafe189017af1ad51b822cab58ee742536b13caedff9f9cbdd7e83d91b42fb8049e3776028ca88392996c3296c447c5a95d630ca0c25b1e0132b3045defe78edf9efbff8ad54b7d93aa87811dbe868232a2dc4ac12ff9ea8a2f8aaecb0b934d1d97018918302a1f1d76460a976424808a4934324717b10c6a607b8f123a14dbd2becbe27649007d90dbaafb085e73256d4cfdcd9dfbddd4cbbed9114ebc5a8feaf73bc817ad64054fae72e8a92e5659912c707ea59438af719d49be77d6b1313b18ed8a7b6f8dafd142e6fb747afc604e1592cc956bc88a221393d8898b97aaaef46e13e5453407782879581d22772da66c719d7b366524e0f572d230acc5ab575ec622feefc8038af4b43037701d85aab1404a92bc03aae7ad82e3c19843c623c594dc7d42c2c8103550546231d3ff7b011d1aa04904b503efab8332929a795c330d017ff22aaed67022d56ad71ab10296647ebb67ef956b8ddaea059eb22b57b9d8eddd22dac53db1f7bee686f9c5eacf83412d1a39f52b451613fd12830f0265e5199b24230f9536e6cbc79307fd597220e65986b043d977204ec1eca92882183d0752110a89a8465964caa49e240cc7c02b3e2e3a2f9ed2debd353a7f482c5187ebfb7445025641e04f40bed23139a549bb1a4f2555e2915da4d1f135429067706dd10a8c1007fa7aa31e202e27c999421bf1fe0713a1d122fc70c51772a91c73ef7e9a24f8ff77afe2a963e714c9b7267a327392b9864256652b0afc729f25c60e52834791f77b4063283c9a49089f77280fd61d477c709e7a4b6c7a4b8188537403cab8251b685f4f4d43c25c42bf6e3591c3a74dc6a2bbef698518c2da3bc866fdc80b1a221c3c46d01e343e134a1c7bbb6f01db6ec7f3091dbcbc1bbc9018b860ea2440652bef7ba6483b66eba7103ee476b24d8a04df0a89eb2c4e3e42497d19094511a2cd0465680ae69d62f0da3f98897b5e50c3436ee5e6d5e2333a768e415fa644988c5f2c4aaa83d6ee0cc10b962c819c66a435f1760ed566f46e009af016dd82fd3fe31b00dc674d77ffa56e1624e95d5e07c3aca66debc869dda6ed3990296e2b7f03b10cf4041b6bcee172ef694a04749874b6372fa94d19ff63e5e8f279df6c6ea69f0bbde90e0a321c80462aaadb8d853342f8ac64f64eea30164e23d9c19e5935607ac149af5d0073114bc0980494b11ddb3f489bee5e528e273743219420ecd1dea0fc40c42c7a844eba3674326087266731886dd33b47e52aa18bcb05ec085991bb20e7e946a1beeffc6d81a672a0f4ac82244bede93992eb58821efa227f3ceee1b2f8c97f2d19a999808757a6c5a53be695bab0e9b97c56cb74d809c915c67ea827607e34246e6718156de18882ac30614a972e8d98de5bc542d778fc2b8c820b88793db9b5f06eb484ca6eb74589f18392b8809277a6166672e7c6636bbf02345138e4680314a02d2a560cbdda7e2ff3667dbf60e40819cc25e4785221bb84cff3c91b0b97878639d6df4056ed44a73016f4a3ee7bc42257328bed57548d6c0118a72b0fa85b924c290d5da2a79a926cbf47490c1657dc93616605c6cb39eff5e47902a47861156783a4945ab4b7831ac7a81abb2f51295778042d2d8e172de4ae2bf5ba1c4a4368ca5ce2e6f1d489a47ce917d4df7c46ca8ed6e9f3a74e55d65a8ae96c1a3dfa6a3befcb336d96f43f8492c3b7aa2fc3bf1dba4bd81e7bfff2ded8234f53da9ebe6f9efffd5e7c232a7d94225ad8a34ac1f133d4cc42a20418f390c064b41890ef0a1a922cfad1a868136308ab350c50a21ad8d8bf1362de12b8ebf32630c31b14a673b3b8cbf7e7fe0ee977b0e838861b94c3a634739aa86ae68fdc6fc3d4813b4f2e1428f803f8a74282ba5c03c2f3f1d61c9cff1f4d6ea266f22b4bdcd958800106b298953505f343aa8dbad46a460b170d0bae384b06299400c5269ab6de1ac8dd6d9ae23d6e952c9f90d5507e3d9d766e25d0af5d52a050c13412aec914c1cc9782f5a4196484add136c08ab43751753fbd17856db4d7bc83f8ae71c2564b7a9293f8e44748a820039254f5b0e27523f8723af1f30d0809caf91d9015e57965559083e8112872dfa02ff4734d9836d96124683c9f35451bbc0f8c2a9721b97398e347c0d24e941b95692e921cca1952e914d02fd7fc087f8ff8050bf8e51b6a68341b655e4308eff2e01caa999a192d6d34e4517c40d9d52bcc919a50aa384c1509c0a2c5f25061729dc33991d73f0344a0e07d5b8528049f62d3bef0c9c54555e94593a6254d91ec1d320a1c420cfcfeac6e99dd47f8f9dd04b348224f9150d555d33ce2a343c8b921da81bb2401d930e664066421e421994a8537581c968cb391760205c70cd7cfcb4d95e3856564c4d5651d71769ec48692a2dbccaf4c811ec5fbe443e78cab36bf73ae927b97de5912cedad5c30c5250aae1bbd982c855c544cf9386c80b608475688810df4279b24ba7f68ac04950b2b556f62715f6d0761b03b857be3092bbd0307d5fc34a88035a7152603eaed1945db14ccd9683bf5cadc88a71249922336478d6ce7a12c2daaae74f1e8c1a81e4a58de217322d73dcf7eb6d12678f25fb47f4b01b0f7395ea7e7f275c25280d76f0c0280bf3bb18059121ee02c90f3bcaaa95d841b1e3c1edc9723c25b9ea7dcad1a027a7f928e7fdb538f179a21cc00db7c50566340aa6cfb61da233b4c91c239a73e5c75673e9d517b64df6f6cf5943e5d344ed8e438520955a10a2457aad4967e32362593f2366fa0e9bc2b9c128983e05e640ecbcd95074fb6fc1c7a0064888025ad5592af87f92d3cdd3a12b11c7ee694ff1c4f3b261f61f2b47bf0015355f7108680485032285ec3d6ad7300157bb769aa56a9953b53d5e68eed394ba9aaaa32089f594c4bb41b7478f06eb724257019d00ee9f047cdc023c92b679b14052a475ecec5d6b33b05c8c80bdc848d05aa8b6f82c31ed28ccfea60258badc28f2c40e545ac07169e3295d888f1e3dd2025716dd828a3c8b29ce56c1f582725f3bce571f1a921c10892b532771682faa879719d5157c1fdfe2380449ead30254985340b6afb6bf4092227a1d4a29842869e675f5bdff9dd156057de614bb0fea4284a9009df4c3c26b1d788202d72eb522485ccdd83144f8361fb1a53f65e88ec581fe6f779617cf813cc5993ded944184ecd59a2f01844502166abdd3e2ddf59946b2ba6a8372c8a4230615eb7bc564d95a9c8ed154b35b684a12be4ab4c42251defa7723ccb1505439a1f6172925e631e0cbe1ea5098527816da4f29dac7855c85c80777f81622a271104ecf6877d309d8929add87e46e33793439532bc14d0abcba7f4d009c149e6535520214be4f6cd93b6d47df726abd1b6d3671f5623ca9b6c6b38e55e127674a0a14c1e34aeab640c9021f6ef0d947594e2541ce49ea507e4bca3f4d063539505eae7c4107f8d20af2319774a5560a01a87e5851e01bf6776e0a210d824c65c5722422e45a7fb8c56e1c0bbaf821334855742d29916e862521b5acd3e6a45a26ef095f1d8afc1f95098057f045022812d1d2a27a0802fa3c2b7c0a796a5740e3696a8ef706a0e5278db15dd1534d20fbe3e1182bb7421626f8cc99840ead290e4f61eaa50de7fb8b1459c0fda6f122ad860a47ec9210bb87aee8f8ceeab0abc2f98affbda0318fb7d4f17bb3b01c4e1ca0bd536114d348dcec891635cd20055a5fccec869140b2964573514fb3d6068e009181bf8ff03402ed355af6f972f311ecb58928d817b3161234c4acbd6566337a01ba5956cc2253f7eafbd02620362483a4306f49c99016a40bb6e2a764fd9fda975eedcfb9aa45db7d69113f629c8376081ec49ee4a0828dd44a6d5f5f21f08c9e282ac3ad25dc87d95594adab5b4d75c832e68c9eb440c4e7ea3c4958ec43986d49d0e70e8d369dc20bb9b160a76617b4d1037f7319b424e77a6e920c3e8e5fbbc5a081585674e4690263bb4b9db6b0aed9a2d62375c246ec979dca761a9c2b5617344cd08a38e1f0bf58a71612bc19dcd215a1d67eeea3318dc325cce78c325afc6bc4af2497e732a3481ae602a751007bb751dc2361c9f76ad625c1943d304aa7380691549d10dfbdeddec6306499b157f20d5508eba988760685d4644f8ec266baf06f7f6dc6b4acb1bbafff1233a5b2568ee10dc8f2bfe88e97579ee8dd3aa71cc0eb47f26e21de1c84adab38f7043ccdf5c7c4efc60f788f730db041a38fce6df8f8891551641c1aac1d6c9acf16938eda4bdd1bbf7827960b99bc67d6a7615c4d79ad31d54e46ece03d1c1ab382c0b67a21a24ae6f42ca89acabe044253408eee973463f747a1892457d949b7b968c033a7193df8e96fe752d22afa826cc1935f824e914aae1bf82b5ee17915531e2980ace1eb614c8bcdf5fa43625a7469d29031aa9b00c37e86c249c077a7934deed60aa6cd8f6cc1fc5cdca0e3ba8a84422dd3daeccfe78f3a5d5c72f615c5ba9c6174b0a9fc3287915a650d4ff833f202383f7d8c3a39b002b6b601ff03e57ab036e036363ee35db3e76e1488cc5e02ff802b729632bada9ca19c55b48b119d22ae909401a7aa14fcab62afeebf9c316bd721d7ed3b873bb73f412d33324c4e2c13c7a8f89affc47dceeacf2871c2eae2f2ee73fce677717b971783e6a053b439ebd0a8d683b7b8af2d94073c6a1abc97bd7d0437cc1a06bd8218a2e4eaed770cb5457ed0571e5d0e022ee1f42837f3b3bb46e87910f25d84c0c6637f889295cb91d462c94f198e9f2cb52d67224b179f08eaa46617ff146edf60cf0cf96993173b8c662afec015c7d9e3d017adebc95d991035b7a98c13dcbb3bcdd4559dfee1250a95308b8882577e21e9c97f3411852b0184b71badb5190fabb4dcc42989f20ddd9a3f0dbfaa9af7118d19912c2002e423adb1490e3e21f566521457f3fdf772246df9245f195254ac35080af071252cd155ee3010de74ee139d7a12c92f90cbe4b3c35086f41339b817bca13844f5e5882eded4cff95be723b4c28c204f7a6a0a5567233ed6b3419d9f5992c69afcf7ec545f10e2200855f016978c9d735022fcda445d8e6540c0cde4f3f6c82d1d6d4d221b2bc814318500dad393900611d48ee60b2460a4ac6c2db62d72bd04af1101a85c5d4cda777056491018d2e98d64fa24f2af44725f3c02644cc63a354a7b8567769ac4b73e62c61a6adb42edf76338c0198e32cb0510c4298984cd9c038174d54adb2eb0d129b9c2b44bc94bb81f8d650e3dc50fed807e5ab7eb4cb8dfd0752987203e8ba113b44d2263b371f464db8a2e523a7e7e7e35383734ca44cc168ca704747cd1acfaae898059d090a8afe02a3d82c8719377f4a26c7f064060a6375fc2bbcea8ddbbdd364d7eb968d06d08bc06f0c1ee8d03dddce68d81cd502878a7e62f0347bb87cd16d113e7d951512f859052cbdcaf128ac54c44ec1b8747128239c00c0af13e6b30f599991d90157747f334dafae1f2ed3740a09b18cf20257e024cef14798378c7f2a3a6568746ec443a33d297e88731c08dab624779cea630c8327b64a22c80aeebc2951576555ba18830c958ed9f68c16a743447b0bf0507a05c7d57bdbd9e725a8541b87eae4377dcde35b14d4d1de2718e09f497687798eb0123546f3c1f454609032751fa4ccbbfaeb7325d268b5ec91040008233ecfe139a4a95f8a08377a0cb0602ed8fd3e6d13f74dd3a952ca99c1630abd8d8406367adcbe033508751b03d50d32d547ddef821db74e5b1488e54fce9756e490a677d4f4019a031719f98bcc9df3f1186062a00b7557793b8d39e9d3ba0499643246c088e57176d36de74b1ade363275b468740f08c234ee95e4be86cc214defdd919e5d76dbb4264ccf1d28e8c3f02c064726f128261c2cdc89445b02a6185fffc9ccb4321869c4d7e9d4e03bc7074601e4eacc4f2b1d64060d3aeec82417d2b43559d6de275fda328734d5bd741fb4ad71fcdbc0fc04080e5fe66a6d1547894c8f0e567d282f3706e7ccc42f11dc3c5456d6ebb11808f3402716c0a3ccb27400dd7013c84c3df5da380f567b9ba6613bd70a5305c6b7e6a4a6b21d6f953ef78bb69ded7e907ee9d4a6faf432899daf4d5d584d8039d563b4611c7c79eb244b584ea002e519992f800330ffc6a5107c5455c9eb5935eb9345c2140cfe6416d0fb29e3e7e03533e3facc72c7fe1f97c56454bcda97c4f5204f590991a5399e8750f204aef03d4fe415ab0d40df72f9340397e456d7269f5f44085e8c6a9c24daf0b441e2e4247fbc93e3029ad23b555424cb35be332c1dd760dce22e4c920e792f70c7bcd47874136d24e78dcc633967c2e75d0a4e1a0268adc1ede23ef749b8a8ab8c493ee6614bb0a10af403763ceed6bcce861fffcfa196f55e92d85267dc5e053ade368e73b633008f80e49e662e42936eec659f2462a7c73504bfc3946039c686ab7f2e56e2a48e61861009179225815c26f0e5a640c342f31f01863d80df23de5a765b07b798cc203157d1e7f26899b865b2faf06bcbc419ab9649a4cd667d5de45ad57dd8d405e6ee0ad79a96725e59d48fde5147f0902a6f23ed5825d82ef189e7007874f3c04af006d2895827eeead0874885429ba91d9976fb94570ca311ad19da16f22684fca54501c10899c7f959047f0ae5e52e2f9c6eabc33f20ab5e6b9dcdbe8dbb7a4014ac3a69160270a22836df03d5b0fe512b31b4f6d870fb8bff5ad21f9d6e8efd9a4e46b2a2a4a7c153c05d61d5642d5775548b0f4ba2e2ce47154679ebfb8a920b926b245174585bfe7f323f7c113ea9c723d096a26df15108a64e1260d5b75b26aa0583231b9f103f5bad8be7d41c7ebf1b75b8b3fb979cef69e86fe21fdfe804420a192ea2a88f15316675f766ec43e20e8ff7f1655ed4f726476faf17457da2efb428305c9a5ce58b3d6453969275681fe34717691f68fad450ca62aee47d90cc174459e4a9270db464b6b00f46ef9ad332547cce14b63c6a5d8b5eaf29abdc04995db952452f6f60cadbb0709721306a788730d00cb40ece629b5f27c0c409126e2dc66c4792710b43146e23fe11d4cec9d25069674bf473e3024c2334dd9a536c501ae25ac7fa23e30e7a3234762c037d1edd686f4a330471c830d8cc33f32904a4c2ebab259ae6c12152fb9ba4d66bba2f102e1cfbace5b838a5a3670f8995e170960cbee00e3338cfe0fcf4f4bf0cee3b58ae021c9c213e442b6237a228e830dba38acf7fb26a2a39dbc742355ed2e962e95fc792fe2333b2c5a3f69d4c6174cc0cdf0f5ccb31e8d1c1b6b820bf2f17a5ffe0c34c899f66ea38e683b0d40f89deea9a867a0ed28931ab9b550434aaef9c37764bfcea2c6c072ee031951759ee7467c61c3ce9fd4ad2ded2106a1158568f61b0b89bdb84b5355d4c970fda9ef1688cf28712e3be76bbadf314fbe9ee68dbd76873c2db441049d8a85d009423888158f72361d16d1697c16a68a4bde54b90936e1b9aecff545e1462ec047f6f5bae4b38b12886284aa0b3a877c8a49ef8ad907c528f4642a0dc6f7913a8082a0952d2acadabb285e23a5c1c45348b201b1dcf3122f6b0adfca88da431b9e82a6ff3ea7d9f38517b8a7704ac15c19dfa1b87c632db458f7381717aece4f3cd9cdb5f4757641cfccf3b71011ad0372179392a4b18bcfd4624d0d2f0c9d4ad7b79a3d66204003697f00b12ea350e0cad295ad108510164626a463aeb54178e00f142a55ed07b454989c7de77ae517f1726beea370b99f34925c4c94ec4215331aa38f81680f41136aaa36493ff690637b6376c57322e56fb0dca60a36cbb452d5638c714da51118533dbb37456d623ebe547a595b3cb32de16626d4ff5f438076a5d613d54c95ac844bc3e9974b0fa45b81c8dcb421c925d49fd3404fa9e5db87f64afd28c54c1d51cced3834efcca088562842cce216770ef75ee5abadd933dc9e107eff0781594dddca9d30e9d1223a0495af7b1e07965d333084224245fdc519ae22cbe4cd3ec7f584f394dd3f62eb7672d3fccd2340fd1673ca36e26781245ca7a5a018686b48a0c74a9fb27d2f4dcb594309b9f8e699ac395932c231700553fac6ef9400e577d9c6d89a03aacb71b280eb21a2f012b7420aa4c7a80421b559be4fa8250851a939ddffde2534faa3bc85c09c28931fd230676ea7ab70d7fa675c64e5e32f2df5a43b5423dea7e1a58238abb9cad5813eaaba9f34a5d4de55ee68b7edd8bcc6a4a6d56ec81aac391594f13cbcf7f9e806aad69185d682850d0868d0fe26a6074ff7f2f982f209ef93f092faac2a311bf651413fd1ddfdd4ce449fed1b49f218b819f34777b16d0be031f41c3399ed7148178e9791667e1dbb3fa1b433b5f307174edef4675a6c3fd0d6ed286890745faee950c8ac9c9ba045c5714406e480a8c2c6ee3fac35d98b49544e97b2c2d8327b5534bdea9b9cc1bc9069516505c42cfa247a8e829ae33b6f99881eec299a5b8c3f1257e4176f9330258cb8e7d70c6dd0dd941c894fdfaedd1a2518d19ce5c13dc3ab7f80a2f2caa9867e4f5f846a5daa76f46d906e599ebdd805fc61d7599e45ad90c1fb81c972e22451b764117efdf86b29b2173d45f04f2d5b65d763736407d86c99ba4077cf05c7b1bb5f3968c6394aac9e3ffcbd2a49e8417b22c70246e077ad66857221a7eeaab31384dc0ac0a764b33089fc29d6b9445db51e60792838ed178a5a0a44bc01cf4d9d95a9b5c70ed8c6eb90e5a4f992abeede8972560bedebdcee177f1f6566c8beabd8794e163a8e013aaf71ede3da92c4635c127de95f3118a2c7a066c54688f1bc2f3a6a1cec9068f10acebd7843e520e55374b1383733a3489219c048519891f36222b289a02020381e639ec143b58c4ac3eae7095a43392404a1fea73da4a1187cdaa24936b3c7e014dc63cc1e93e44c7ae8a655348075d46b0c651bf013492c2e563a756c0f08575a265d99c8bb632b521a80985794390302dac2062989aa345ec7924abd6c9d1eaf2a3209336d347c84e9b480eaef976b69035f343144c8893ef83e119783e83fad587c00ba10bba0e27d07b2b64cc33787532d963d75e3ff1b80776018b39ea48b84e6e13c15c71624e7aae62b8e1eb34c66945ce8aeaddd117cc7b9f5a387d0bbfd870745ad359913fe3fa3545921e8ad30071951635d5f142ef4a6ba8b5177657a922f004583268492124e2acf80e695ca20d491f26329a33edbd662f11a00850a291de2aed3452a271a7839c080e36593f6517b369617a289579da47522ba9c967b6d8ad1c27930014b95ceba355733d29e8c11e48cc1392ce77c6d4d34c35ad68cb85409f21d5a91647641d180c70e82540d17a6b1dd5960bd05154a96a5c11edcf90568890452a53d1c93d02cbf27ba67544603eec9efc1b66330bc92ad58840b89191de1f53607d9467fcbc77ae65b3ef9a7bbb2f2be8dc6a11d84afec1a37c3f6a22af71fe53e04cf7461954ade9bf3f7e453b0af79ac84f617eab01b892137b43f626c4a4aa2ac158106fcac587d56b0b7ec8d8cd43aa8bb3a0ab031b7d583efb358465f2e9f1e3652174cca0f78dfa5c2275b057919609189f488ee5d7780ef7da795f69372e0cffdfde5320f07dd804c45f356779c34581231ccf9a867c403777f2184db9e0811ce5863a0495148f6b200b9589965c0ad6c7b76e09a241e5ca65aedc7e53c4eb72a6bfe6624fdb147938dd6c60b0f85f0f02bb527141513b01b1106b728ed586d3d0d4050c0bed1303f7737c7091809ea2c8bf5e69c92ea00bd281504bd06aecd4cc71a886539e61c476061714cfccb5efe3f6c7ccf93e0a51a54218c1babd0a76e882e66d6be18e7f708801c76512f6db6e68408daddfedb86f7f43bc10e57c9a275875b241755c7e8a9ad8835dd17e7f4653240c63e7c8ba2d5a76edfb28b64e1772f52682fa0e34133f60cca0160905101e41414bf1e191e2c731407b7e7ae35c0bd831b00dcee7e8f329dcd770cc53fabf9cfc96b9e9f6b6145b78e57b103b27445000325c90305d584b7b842a7356e8187e2c36b85e3b6f2f000be6123b34513d9fc22c430da358e75fedf606c282ff2d15e94f34921611fac687c8a2308fa6b2329acd1e1b48545c15aba82206f2c68c62eee124aca8e174ae0ee61f5d14bad907eae6fd88de10611bcaaa0bc60ef89e4e1f510ef451b7f39926a8950afc90e69286813787f7df82b26e3efcabc7ae014aa27f06b5b3b4cc94a3128b79583885ae44bd6496641d99d8e7b7d0e612492667062aa7fc82a47b80b154e072b2c2cb208925bd3832e622b006d1c30d21ec42d6bcf58b805caed3dbdd53f6cf3e58fbf48c20c14eb486fef3cb3dbacb5af4d1b8a2ec083874dcb78c64ec8b89891c0ba908dbe494402436e7bcbe8c45518f89195c7b1dcea2196026f85001e43402b07fec8a070ed3fb7117d90a1f89f2d3724bf61cb8a44227f2974f358882f7e8eb37e4a3786e9f680edba0e46568ff5e6bb2c85f4c4cb890837db215d8811fc4c238acf3f61ac87ef1defbc42a15e3a2bb176738714ab8cb19a45e3c85cf1cce9f5903e866780bd126d2263cfbe11322fa07999a73ad10e3561ca9c2a1278748d9c4beb762bc382bfbbcee31d9e0c714d6d4b4dcd4d534f76f17e5e0c8dcb24e3d0ec8b6b21af49ef5e87553ea150a8da66d8971f30a365f7ed4f65a67893200f8ff03402e9bdaebbb49f70461156a7ea5712957eb1ad666cf42f248b8f9f5cb52406c4c4224d404be0e606e671476952373442a75f7ff137635ba72c819093a141764c668e72eaf53a43632b60d51abef35f165ed18498832949d935bed5698dbd6dc600298de3474049e4c6b9461dd14662b6808148a88ad8942ab9bf73f024b4cb85066e23286d2ca69e1f90de2e4a54caba74ad8b17ac04df98c0970eba3143ea9bc52302d593d6b2ad4f082adee01cdfd68044b118e1561f46aeddecac3b131173247431ec422c6ed55cdf4e35d4beb242d487f0a5d4b53544b577b8c4086dfa8aef67bafacaaaaee8d68a242fd26ad830aa37ac1f873b4c7a8bdc24aad09b949d62e875d3e17666935b667d8d3fd3aec6413734e6e5c0ad47e466cd82cff0263cd7b597c9026abba2717a7cd083853a24fde0de7094fd1b61379a44912fd3a1dce2c74ef754ee92281084747b18f94ecc1ed33e84ef3cd9c75ff371fdfbea6f002f2e7305b2ec331ba000d5c5bdef320fe18b33981d759346a8dba055cb499be41633d3bcafcfd4844f789998a4818f0d99b7aae9810178bd6d03befb4ee488bced5f5884862d09f2351e96965ef1f541151e7766a136e2e3203ad37ad3a89159fd16a5cce3987150fb265e339b6fc60554ea21a3035a375b5a27d854f3d7241820e0d3e4440b032156d7685541d8e69fc20487b0dab04fc88b9fa269faa6fe841ce65769ea7f0b800147d67d9a136bece6c4517278415d9b7eaf9da8c2e0e8140c6bcfed5aa3a971669e8b88fe92c7e0f1df6600c0854712d0d141bb6ecf66ec6bcc4fe4bcfb180c1b69bf902591c0d93ecda52696e42b2fc10f3379c825724b82a25b1eeb6cddde556e2818aa17a5988550b4c27773c52cf7d5976594f76355f5b97cc163e317afe484bc9a6cb5eaac58ea49b4a22d5437cff6ef8aa3b8f6c40900e81b64098ae3139bac171055a412830ccf9e2dcb2011aa029cd92937569744498f6793eeb1681212cf29036a62a637655627e8a77d37f3d228cb0803dbd69a0a7aa79c6432ee1df91035eff144f569ead90d91a35ef10094c3276f1c9a44e95ef4cf6671f65ee3146b9ea6a3dc487198c966ca31aeb30b8bb8344a5733df519313955759cc486efdf921bc1515f862167f319f6ad6c86e0c6efb850d8a39fe7ee9a818177fcfb7c7ae2f7f024469fcecfd39d0767cd5c34c5b5666a426031d37276eb93dcfea1eda1b50317bc97dea71ec4109f8f96a03dd1decc3745edfb6fd9f9ae5be2a2013c3cc29bed293fdff16cf1012b4e91276c5db7163f39c3766916ad4f72273c2c012242eb6872b35de306a3477748e94cccfc9016ad51e567aec143d0f51c1486b9677ec790453ce4cce754083e146c7c32fadce8a2ab400e25c0dde33359c79ca57c090dfe3fc704a2cfb4fb47bfe303f814f6522b2a3525f55d64a60b3ed46edb316cf4c5ac59dd7d013a304d06aeef258a28c5b995ea56c25850e46eca5a99829fac78bd38ad5659303d2428f287b6fb9e23505b212e58a431bb0a04f19b90b77be976411387885437e800dd8a9d11c007430a1985fe9c51490c4aab301be7503f7715186a2dc7447b919390b3b1451b0635d00c5bdb1904a09681fd74a3dbbc0abaf59345df9d89568f709c5534318dbdd7cf1bcbed32ee17020c10773a802ce8cdaad70457b89482413b3db37e519608b9faa5ea7ec34bab99e0289cdf42527c8ab57bc74a6877c1c3eb486e8d746f872f72309fa6b7cedeb39884dedd9f0884f1d3e6f0b91e6b13e457f6b6b4a3cdf4d3532c630a8d8170c05af28d3bdf65c6debc038d135299164fc754c13d26320cf20f9732afd2dc64ab315206cb78d3c23e9f1acc4bb88b78375d16796693da3fcde3a147817c4565c29b8f454d680ace88f3d8c738eef6dc610e960f518899a416d4e1c5a581d5d1ae9e34a6834749f284a5de68742f5735d338bdf5a1c3bb18d867edb4662791791f188135fe2ad8e22c5907ec8a4f8326da79a8561d8fb23b8e89994bdd4a2b2baffc96e905907fd59e78660ff401f2e85ae883de9cce79e397f7819b9c1e704962be1fe12de3d8b3432344b3c462fa32b42b761d5a9a2e9e7389505ace2609bc10f6880da53554c7a0e8994409083f4eed5442ba6ae837ca5c70b1d7189dc0a916c9ec5417d484b8856dd8bea0fdc91fa395270a54401f0ad8c861500a78a43c6fdf12093e60afdd0716a07ec14f9e7f7837d9ee5cf4e99dd7c7fcb0e8cd771d1b92e154864f98e22ba4980cbf0899bc86177f77bbd193afd959844ca6e63a5752b4cfd22b0d7bb288dfef8e9372209064c2926b3e1fe938d52e7458814d1522f02422bb1913efbbec544d775b4b92879eef5f7046f3dc4e7b6f4672d8c4aa8451d603f1bfa1e2345e72016fa865bb6098935a5ec6ec510bdaae8beb8e7d22f75524e87558868ed7c2a779e1103affaa3a1cc32dade691031e1153d1c8f5d5ad4010a0d47b5c1a9229ffaabad45a45c71f8524ac47a2f05f16bfc1e319d6f0f5c2da1369768c05c581ee345b2fe876d99aee3f30bd44cc487268b4acd20394d8aca4930ddcd2375e42a00a4141c4ca06b8173749540011d53c244089500c7c48844f662bb54367ba884f8f4a8336e3f87b0dde418de7df5f041adf2b32bc246f800812320d0d337727c918262e9a46d548649bc698dfb41d40e736aa5ee6883abba3986157c498184129d6ede694df7952214dce951f28b05dba4bcf7e943f7b838c3fea2dd10271bc29bdcdd33df45f98962cbf56b6bfe225c720886b7fbdb6e6d3388fd4b53e615d174a51575c6982dce9eb769190295962204becb145818234a15d1e3585bd7dd58deae65440615d60179a8492ca26c904495f0867ae98ae5a3f07013042014b4b34cdcf86708f0b264a2227d8bae166b8148400e48a2727e0a483d66fdb770c986abd8df4c40e0a875d84de61b1933fcc85acde21d1eca7b43ee800903a8e380553824cf532a2733d56e942c1903c69a45c029866435997f0bd5dc4de0fdd5376e41e7ad5ec04e90a5c426e729f007cd4541fe9c9e54361db65a4b0f51c7006d86e3c6a686dd533bf574ba9e83027a5225f35408a599f58ae03a7923acfccfb6e11a8efe68c457aa496b3f02e6a2ee88fd4f23a648b0617f60641b33d8cbe2f2b6cec88d794402d57fcdd01cdaf77764769c0412bb29af2a531f62365f161a91c505bf89f609051dfd2daad30a0b56453c88ef1d17721d08c0d1e5f5329595a8e6b52e3f16c6aa3121fad461cadd4236c10b0309b900e2694c2a8a52e9895fe1c76ab767b81f672ecab5bda445deac38cd4b3453e81c8b6800fb6834eceec5f0e7c9cd9196351deb667948f99d05eb347ba6a6c4ef99cf1eba754c8b8a3de7d2bb7db53b0c766e4a518c753178193ea8037580ee9ffd1bf5f9a8fcddbd789e9dcda946b856fca44380b54595fd9840b17532995a1d12b3625be6ba56aadf82b75c7b7baf23747ab380591dd013a3536887aa96256f22e922534d8962258b81682adbb83cbaef1462a622ed26696b8139ac594f74a0084dafd797216b893c47af0d8132c70851b52e7d78e47688ea7ef8e3884b48b080346ec904c924b40856d3b63a54c2c72c18657141323477e690694a9a1d0f5205e2f6dc6084da16c92f4c0e72dd08bc7b548b2ae958f3a41f7b34c7c7b02cdf67802e83a1582634a5dc6f7f0ab6667cb787a2adbfcfdc2bdf1fdbc4be0aa29205eec2b8e18d48220760d905e2fa24396427b7e151a21cccdd1e48d0c88314f9c1f9bcc7ea4ff9d43a031ef7ee2cada827ddb8cdff62c8344c6fc6a22dda99740c453ba2865834a049208ee201be0d8f36b4f972593b8d7a0eb1b7b1074e67ee71acb590035899f9bc97b0309d3bce5e233d445a1cae26bceb666c8d55e3df665cdf4670bda887506e3e1c76a39b0bb78cd0f6bb15342f5f1301e6d4283d1aea7159fa0889f869bce24c932a210a9ae943096cd2b855fbc8400c71fc4f6be7b6c1ad0119e5b4656869e3e3170f25958598091ea80e6fc7794795969ead77077eefa6e2bf397d8abd2b316260767183e93646c727c9d5f55651bd2b6a4d4eac7e1f9e0268fadf280fbd631282e8252b5b7bd0d3acd9e48663db3fcfff75c81679375ed647450c1418b13f25558c8cea66922dd76bbc18433456117702a3503543b625313d5abe0769be605e9f5e01e66043de186ed1e028e2464c6b3b2153534eb71c3080ebaa9ed1c59f9269d11371015741d7f683c2f0924fc1b41731edff6401af5190b590ba5290043bac1637f503c210739696bd5ffb91e68ec5f743215a9756efaff4091e7a6f8aad6e00ff3a0eb90fe58d511030c4c1e20be37e7aaaec705197ec2aaeb6bc96b5d68a451e6c2b03b54888b4846e758d86f3c7ae52d1ab810051f7b3ae7722696b1816709b20f4d84d1ac542711463fa335598a29769360f3215d4f1c715cc7a9aa8c29f34a57b92a7af5e4514d31576d6043736ea514d9c97be36fe34cbdcadcef509ee1bf5196e5d28935b854ed99620de312478afd5f8f9095f8f3f0059c3f30f4327c28ab4b60b4c1bb37e34b9909918840b3c204246e18bde917cbdc5dd47f7fb7ddc7e9a20036f03fa4a1369eaef393fcefc2694e50d83d9f8d111b123904ed0e7b9728949f5912ad5476249fa336f16e0269a64acb9f464298586d262b051446297e79dba35b90f58bebf2cd0b1aa308340f147bd2d9ab21c1b07a8f8d7cd83e47ea0c4fed45453eb3bd97f86ebcc76172e8703000f8ff0340aebdfaf6f5bb49d78c1603ea49aed84ebacb5df4aefa5dc11296779e0005b015fbfd2feb27cc470bd0389cbc55f5c474cf1036106697b4bb64956255bd373d6f7ae6a71014e0a2c281746831dd3f26a1383e0965b118aeecd7e5340904d9f5a1f1f23ea4b71594f4c4b75cc69958cd1168587bf24eb81ac85828698920ae45ae0b384d2a36a984d4c58511dcc410c644e525c82e3361edeacea41875538847a46203c5f5063df85a7fa78ed515a9d2bd6ef9e58f08f9d344473edf0809d44062bd769ad7dcb40ebe9955e072f65e83840e8ac363d9d4aef29afdf5b57ff26b04c5c6d4461a33f9a457c1f9ee1a3527ba868f0757fcc21dba342e97d430d6b7eb6070083acfb64ce007d5cdab6be3edf3247106e02a993c01ca35cb8d8e775c9d7b7b3864b50852aa6f0d5c896fb053e47dee048a57895a5df741fd7d3a985335bbda806f547048f32d85906cb82f63c031ed9ad45a306fb0301ae40d3e44539e25239ecae9e8f063733a39a4d47608da493d2b1a5b647a9c46de9adb8f6a4fff64c3464b996618a2edcf1a6d2f4f178b8308564012554e26f3ac12270fe77a52c3c3779cd917217422eaa862f8d876b60f85dab36811e5a968a999b6c593f924779a4ec8004f407ae429bf7415024095560f34074380c3307ba199a0716f3aa80a021121e3e68408c366f3bd345ce7106f4f78710a2b460326f53203323db44635d11a343023c42124ff794e7b54ca226e8350aec73910c2e3e584cc13d71c6c250df319242f91d8f96462f310c8c3c1448191193b3318c3e1cb2e911d105736689cb2733b35894ee728d1eb9523dcb978451ca28412bf949b8b54f70557cc01f8e41f5a7e92e245406d1053bb0af8fce8f8d7180d0c709481f59c795a46891e8dfbfee8bbe59f8256ce455d693e770a3d455bac1c096f3b2a62a8f641846857c6672c03d0d3494d9320a4c9c658c15603e85b6a041afd99adbbea11da768b777a998c657e23a3020c1a0d500df81d557c1503a788c07c25583f6cc7cbe16a20c9fdc95b7efd553986944f816e3d290a593f48631fa118cfcd61760e87f8a8a4b1d38d8ac67d37b98dccd0a26a1d0a63d219395d484b96a626be3ee8df6c80ab7007c217cad6e5d20c5da97d1fb1f19643e30102d20acabd6496825454f9632ad19703bf29475cb050b1e502d6c45fa5e16c85b4a5332830b0dc04e62460c1c6d98238c1d764d86a267a5bcc9b5258ba677aed44165c7133eadc4ad34810d9c3588901a1418bd518807b440b4dd161793b3ff69ec86643e00238aa74eabff9870f29f034b824beeb716b914389d950060c7b97fc414e486b3c388b8aefd97e011d82b021b13c498c9a762849981af070e6723ad003621e8a1eccd4c8be204b33909f282f5604e762f0c7595b580acc994eea9bae53619f3034e999780bf4d256a1338e99a72427eba7e04e2ab9aeb0a181904425c7041fd5ef85b39bbb715b7ed444219e3a474d2732291408064e5f87d0c8dc98c880a4d80efc4849fa84776f3a13e771e5a49dcda1db189e6a7d9b7aed0d9c75dab5c9642235acd7d9255bbbfb3139daa92622ed346b327e8470f59c2087524f1993264a2e8486c5ca1dc3fc4c79b8211d0033fb443eb0ee12f0d9f4647e08cf571db19f5c42441172722bc6511ae192f329ac5168b61b47f4d7639247172b22acf63333ed9549226c0a6160b0a2d458272e227bdf77ca8b07089b2a98cda4c9c75652a0934f0304192123f60092c6bb9b5d8861cbece49c21b6b0aea3a3c210bc98b666a7115658b584103e2c6eb64118d9e225e89452047d4488f2542d052d93654822931894673d966756ead83884f3413854d8113e044e8f0c402447ddcb10ff43b9f4ac04d1f5ce6e34040aeb78fd1889428f23f6e0c606087745558516cee6ddba3e7c03684ebd07a077f7867af08c8f3c88b8c585c1e2e1caf56a852f2c00791a6bca5dcc79f16e17735ebcdb6855b26e0cfd85ebdb5ba9acf6b0c540cb27913c27ceae895367d8827a20547cb819f7cb958cdacc9eba1c7a67ffa405f03cab5d26fd3ae96e1960c0d85a15bb67f9aafc4dd866a673e0bd3c6bf5a05d54ad644df4a9442e3fa2aff95830bb4a37c99398c7005e7f666ef8f7bbb38a435c06487685aa67853796f34eb943cc5dedbad1a2b1b288d85c255d957dc8dd01bb6423d910969193f308e7085f7e263a579e44fc2a8b713073711c1902543173c75b322ca17202c8b986740c922a371760c5c32837e7b65bfef269668fc210901281801997b0a9cfa988ce626d52c2cad7cdc7f7317c0ba9248fb842ddbdc68210ad2ede2c1d8bda06dcb8c30220b229987f373a11071d1addc8a46afe034728fafc3952ef9ae487cc28cbe5cf374fcd384a3879bc7456d05d9cde89ba21b0b4a6d0faaf86b01bbda8dc8f6848ef316ebc6425610850f40fe71f2f56790a22de3c0a90f7a15ec1e6a27e59dd18af283ff80a41b49b726cc99cb4b4615f3dca09552046e3fb0fde345210631606ea9c4c9e71a7164d6f82cf93a3608635f90b654988bd4268d9633da56420d7391ba55ea33f53aceba49dc0f116fc418f5e8a6243389a006ea954d9f984f24668bd923ba7e9721aabfaadabf6d0c6b3b60eae1993a74a26f5b48612c5c786ba8cf01a16b207af54672f016fc5bc21d5999a8fb31e2ca3b24efaa717b48f31f8120896f774bfaf21fbdf049c89f32eb98ad4025f8bf11f07a1874924ec6a888545e460534a2f6788061621ff99bf3e13d961612c86a8fc02fdaeb1bce8d9f2a2afbe82f67d8c253da5643bd7138c97c448b7683c72c5f91b78f588f2ad736b248cea2b3b6d5ce49d7fd7c1ba78263b1005afd5b830163b2f373be829f6e48bcb68afb0b920750e7dd2f7af14b58db36b896ec8fc60421ef12a9828d2035d99fddc46bcd4d4d0fa3187bb4fefda6ac27392fb9b192f191715af7315843113bb401ad139d07605b2394c1c725d0afe265592923961448d48b67f98700094bb5e55366e7d60aa575a166179e8488be03deda65183f33bf45066ae0a237cf09f84ac72a2d1af859b8e975ad2fee8a62cb0743ae6948dd346bc95de34f762d28401acc5c7af6ff9c2196fdb2605d7eeb1c86be4b9689626ba0d99062ee71a19be4bb2e1aa94d51563ed6dd6681c4e8b66027d236407f1247eb98a8c1e29edff4ab84cd378036506e4274277d646c9812271762fe8ff6e7bddc88049e6f1db6a493091cce7ab47f3044a146417d444614f90c8725cc98888866aee30bf09c6c578364e774f48d11ec27af88a27edf758475990f6470ff78fc9a01a83438583733d0e539468fce23af78f9b782fc43943b0382ebebd2165deebfe1244a2fcaf51359c977953664d59661597bc491ef781eea0a4d1da880a9cde61ce8b58a93be63bf040e6257879544127d6d93fa32c0ad622c8b50585305fcc4d9b8797f79125c27c50355a8403126864669e831bbf62aa21135102caf418a935197b61090628661c46629df375113d66c99c8c4095e460926289f8d45ca0104ae539e665b769e970c08de60f9de274ddbecac84530901d2ac1e0ff15982d1206bf296c5cf3a388ee0af83c9b3013b48bd6d90cb7fa8d9d464cfb4c5e72770ecfe0bcb4823b7899bd725a582b905bd6f897c9d95846eb87d627bd8baf8baf1e3e002eb3b8ff59c1497674a981ce19a81864509225cc7de445809ddedebd1035162c8f61dde860bb205435d0182ada95af7dd57d4f11fe70779a604d422d60d8811846ebfab2f8520255e128b42502eba8c82ec76e536baae830d478a05dfbfe0fca06d4430059afc1620ac7629cedaf6428314fd2c3fc437c1425d81c13bde42bedfb3f3620ee550350279fe1875bece193dc5b0349ee145eeef7eb649a364bb3dcaf4dcb100a14d01269efde4728f2cc0aa87282a56c346c7aeb0820846646f622cd8c03bef58ecf8f6f7728e40a8fbef7f177c19a2426b0fa1f5a6a35ebaa48b28947584e7bfccdd9f907a786d2424b7ea7281d34d129e9e88d6d0a42ba0ab8728830f6586747b282924c922e546383b0d43257af16ac9f5b71ed6a5e71f5fb72132304751735b8406750a2b387c2fc22848b9c7254b4481ed0ec40b7d4336d749b1033784babf214a7dbfdaa4ae20e053ded5a606b148818ab3810aa01880ab6e75bdd5945ce5e4dfdc18ee861b127913df65f49e1326174084c56f870d3575dd4d61f2c4eef3dd93f91fee32da2a2d9a249baf4b25609837a4be70523f52001974bc505eeb1b3e2eff406bd2c7d49120b7c5b20bec647b826ab45ffb91d678df4df041784fe3aa26c64ff79be5ec9a9e106b994989c86b4e56c771b10bbd20f3b8a51af16217ea6079ea695eea67c3cf03588548ce1c5d864a0023d7859be525b889bd6f35c1b9bcfdcee4d6c1137857b217dae9e37ecd494eaddce79f161d29c7521e55b7967401c10bcf55ea48ea6616540b83ccc46d16e93b4222c3e82f512c93a015950d1bbb5ee4c72c7f0295ad25735fae0caf1cd46e03465716b5968732c4c9720e75772c7c1f0f3954865f7379bedacf094d647d88cd2708cd4488e822ccbdf6b22a739d2b9a5384d936b32ae2853f11bb3bdf3b6b7535499b5c7b07e052f49aec537842960f24cdcdcb455659b5df1b7a97caacd6a9ec0091a6e2ab54f8d70f9d572b955665d0f6ea0a4691bba0d90d2f9944a2c950c819d1b656093a0be94db4bd972bed12ca745de7f09154bdf4ded56f4976206805d2411bd1ea4899644fa161b6885423d764e994f08d3506479d4b2f33a3a07fe9dc99ec852d4cbfaa27f6f111170d89aba317461b677f3bd4514ba3b81e170a03d234b2dbadb7d06f35e3e395cb27c6f1142de5786fe0d96d7000202ed8982f00582f05864c2a6812cff0024e5492f79c0c3b4d72b27afabb7d17455d3d090a6598265b112dcae891b48f24f86fff586f7bd0ec976c10d67a867682a50c39d6187561b74fcf05cb817dda68441c0a4423c4e244599dbe66304c431e9e9830517abbf41ee1c03ead9b8d48c052baf8cf97d9eb0caf47929372a846c34e2821de8629b8c9821130c4e1afb292a61c1e9c4c93e4b900ef6a4cb693fa86f8873fcf60819e10364e6307e366c9c7496c4a9633e9ad20c43f05bbdcd18861b84629437e5f414a241cacf159a82f3425367b0b80d3f731b3209504c370b4fed2c6fbca4b1ec4e13acea61f4190d8f02e1ca4e9d7f1cee9471a854fd604296dc172dba12308d67a3d4b78dd533f98460860f71e45b6f6f04a2d907b69612f60dac142c9925864e8220d9230b125ecb54431d042909a76b19ba71215f5bc4a645dc0fec6093973f379a58c65571f9a5923f83c5d7c2497e46ccfc763563c587858c151f6a18efc9feedfe6ef96e3465251913accaf2584834ff0c273c8dd5907c4459a8e5b3e14259982dd8c09c6314c8899eb10f38f896a7437b8e32486ae4c12d0438e4bf52e3e6370f1ddd1ff1da2a369a700b38ce265dd00ed158350624101351361cbe050a6ee9905d6d7aee7fbd88be54d52ec4620ee8c47ebbb398a45acb3e401cd2d62087289e3cf1b826f929302323de67aed2760473dc90a6f8172a4cba6762ed272ae5ff5e5da1a893aab04a9923adf6a2345e68ecc3a98107eda0d9418c020957b9934a5ecbbaf1a7aeb400c71b0aea585587121acce30b41ae0f162b9615bdd38b08aa0a7ee3509d4ba5839583505519da52fd9fbefde07c589194743c01ba1c641ad7cd5890b7541275d16588da0822e071df8c15f3ec71b7239f6b88b9a303f7c978b7a867afdd2c63340494b8cfc62d7c111c010d251b328a07cf7ede7ca3de02c475a2a5245621344d384992bb6415c060aee1937fb4d952da36430c014870b28a456f4443ff11f938cb4b34183a3c7753efeb1525090d5f1df5035c6a8d8421eeafdc9681b7575cdf37a7bc0dcdc7b249f2719386a8efa61364d2a8c90dc1a121b97b121b84957e4142b38297276f00f8ff03402e9d56d5ee858c8402c9eeb02fa4b40671688ee0618543d37dd17dd17c5fbcdfb7f6bdc7c7ba38122e3ac245b87bab5a0c3cf13f0798aaab7be0c12e7f0cb3230b24ac7933bb3f442e91802a26d256ef8a1d6c3d3a4939fd572b07a1560de99cc13bf55946d0491432154fda2964d301719bd47ed032cc27b380e9a482bcaf807f0820ef4133e6648f1d915a8eda4e692be7bb3018702d9013ca71580cccae17f46c194e68cbd0dd7b52d924ff0432c124e2d7813efd29ac9b6409dc056a79fd7a60f82d6d77de0426cb7f76d13f75aacccb9462a63acc812c9a707892530b74c73affee846468fda565eab9deab903c3d19c28b55ccf58c72a06221bb17df97e65c529ed7cfb1f77bfe6409972dab1bb1cbf84ae206a8f59e6c9b7c68452e17702562412e8ce0a05de37e8a00231b2d44408bea617a55f3a5744978d3b2478563a6dd5012361d451309c913162953eb91ba907921363945c0aaf215013c26aec6e7bb08c9d1b207ea065655359b4f6baa0f6b7044adabff92e90e63e65261772c3636a944b5223223dae84d86a2abec4287f386488cb019ed79e91e819287e413bdf11c27e4b5c55a1bda000b9b2421a0c636c96b1d57931c6faa5cd31481dee390b51b479363e3de510e41ea76c1198c478635ecc4fc6298b8fe1344bf96690704b3e8e334a3b331127e7fd7024220049be28fd17cd7f392d8cba383a35a3d936475a8f40c28a101e32b834738731e1ef0c06303201a044381f98341147b6f9a59a03673f8804466b54dcf53845be0c40e5a050dcacd8220762fcf8cab0db6b94723d0d57a5e1a3a4170e1c5967ec71234582432fe383221a633957cc9b9761ec14589ada5a9bc65e3561cd716b0ad1d1f51a8a0ae1ad134be5c4c90f30d8390627973e03413452018eaf3fc894809388168bdda738a981210849de732490219098e35630196cdfab4cf6d1f8049b687bc5de526761b2219d840888b9a203cde18f8ef715d3ac59d4f658b2fe12e1d1836d5a19309c251a61c5f0695ae8d7a07f247ffb04ea350174a1fcd8c6b40dba1c8f82cd3ebd63a802cac5f92d54ee0371b89b8cdf2d4cdabbc5a2d7fce4b2dbcba4ef98d0db793599b66949f0237bd6bf9c899c867944914119eb8e7a4261caef35a65766b93193d426374ca91c23f0e6f4c8a42f6f9ffbf1d36e8da7a093e789a8a96264e7a799ae3743b9618fd81cce03075e79bb0fa95308487a688c247d7ab5afe332f6ac6a3428af3abd6d173885be037d0dc4ecd75962750d5e96ec984cb34ccfd4ed520f27540f3ce1d727a6e4f067a247ee68364e969f12c976faa1afd690f0f514db39ceb151f70956b1d0055e8dd2d941ac1ffbf7ffe4d536f1d27a832d84b9a098eaeeb4c80e710443fd3f0eba456ea2c6ee4af87b69a733b7596ce90ca1b76d7f8c50ea644916cde1a9eb07514a031b4718e708f55736eb84da3df8d232583c0bb8d4b7417e78a9cb834eebe34c61a9a75ae4ddc1cf362f563c02d5a794cab180dd2984fc80b3e305254afec32187a7d5b6cb5365a695c623478a553807545ddaa9f765bb649b00f6f683b300eec7fb8e85a3c60438f6454251ef414cac5444e32800660460513a2ac774542dd1e3b097c40450be654e2331b83b26e83295cd5f47a7775f0663a9be5c60fea63137361712dc8ccc2353cbd76469ed41a580bde70aaf61b11dc495b507279b6065f8dc1abfcd9b5ee445567915c19fa3658f2053fddb316041e318e25967d81ea8bd591b5e3206670efbb8d6b6493add7da7d67549cebaa9823629920faa49214213433155f6d0b467370f3b669a010c9e51db66ddbf937678fa59b17149ee44d8056476f99cdba159731393ddd769313b34ac061d61c6b0b82849e746568ebc19788db6755f9062fb6f683438ca6d2bc76c22e870cbc32f9716ab5aa1875204e236b845c23befb46f01f5d21a33822d87746279ba59042d5132f022f1346a9e389d840cd2302e423e32a68344f9fe20ed26f3a37280e73776ff3be1219f2d74d2b91b6b28229d5081a742fa3d2247d919cf9d95f01bebb7aac0b8bf59c553a9546acbd7e833902c7f752088211cee60cec83e49e4b1fdbbb7307b5f404b727d4c7a164cdcf300ff413d84ce4e6e7a217477b05271f993abc9faa2ed6833b4290de7b411650c3e3b974ffd40aa779c7a51d5a45ac569cd607b9bd6501a7406a4e9f1f47096c532a53e5aa9986fb0338fe4f576e040cfdbeeaeafe6068b120cabd2f5d82dbd824d878a0e47ddf92f1029ab48fa550416a51899591d6f3ab2edb9e52fc2e18ca52a8b0b5944cf0e9e64cfbb792d52ec51741d269cd86f1751ec481c9162aa4189e9eb5f6ece517ab4e0378fbd2329dac327811e7bbd29800af3ff7f0108d3b6c05086b5a181830400819c8cbeac383bf3f96458474352e2e36a39d38cea2cc7f37e7601bf65cd192660c1a0f897c2dcc576c4f28b95e5f0b025830bd6fbba0126e68cc51d429736c78a20d4ab9df9e51465142f1632f0173abc1f00dc7942599d68865f605f36eb26637425dc339077df06337d0fa5cde9e2688e302b45b1c84ad5eed4762ba6108855e0c3312d7400d11a263ed51ecc260ca8a239979ee1b75b86c674b277f10a9892582c4e51e649e5d78d2cd9bd9791445ce9c2db23bd56d9ea6b10e649e595450a015b6768bf1960760c1e9debcbd0994507a27f7fc4ae4e8449165014eb1c33312c9b7e38a6998d84e05c08330fffb96a160bde7410ccbbfe4829c9ae0e432605647ed8ad407e58992f4fa626b70310b2e8d60606c71c7b7c8dada103c432cd428fdfdb8588c948cdbebacf90cacbfcaf5d61eb86e096fd5da86e06cb4903e4ea7025bc3c6beb6c912fd3bfedf12de633586c99402fa0ddea47eccb01f59868903754fba2f0d006e4a1d02e09f3f90fd5ac3a0d70043aa144253dbe8d1aa3d9ff39d6e3f5f71e73aab633ed812a24ee29e6f6eaf6b8ae36eaf3da44c634629ce57ee2163f563e1d9ce60e3b38f48e1847dd2cb15d5bad57eff1660dd1641a08555b2106a27b04885e59cf3971ed4672faa961088f468d26dc1c255950a892ee465145d2b72ac30f97f2e3798bb003319d27f4839a0b56e247d637c94d52502bdc43e3ce57949eef74e96a6fda04218b2529371251b19b698827c3ec565f812e7629f5936dd78d4c664ce58eaead6098f220a02413f8e81afe870b88644d1441e6927d5e0ce194ef08ea10e941ebfba943d6fe6edf66c8f9d31258207137b1c3110245bd079a13f2930b24cc05277850efcfcdc4c21f3b48633c86de8a1e37d703a533ddeb69b23de06680b1283cae2bfc232af7deafada4fa5d7afc9fb2fee86c131e5f0ac01215e2abb41e265feeb21784e848c08501fee813a24395770b86aac6f966e92f06cf30a83dcc720c6dc4853a95d8633cb91515fa7d57e490f9d236512bc5450157c1c39fee2f8629622e0360cdf69b0a08a522290b2c365dd53e323674d4063baef99a58282c031929738aefde490cee5cbeed034dbe4200cd3780d85412fadb7c859221a3847d7606eb2fdb401c4057c29024e82f3854cbc958b4ee6e1cbfc4b1732849228161f6968501c71916eaf6a7ee8929f0887dcb5b563a469fdd2c204cf48095c6c1b5fae9d85592371c5510c89b08a9cfa305d83ec87ed537d676ca73259247ab778d24f19969968e9ecf0ebc6fe99e227e7c9cea8acd6b6e22885c9125e8066753bb02c6112658c9304279648e88ab25d8d50700a1623da5c9ebffeb42707426466d96c89e9bfddbc4ca3afec8b6bce73018b2718d1dd21c306f2b68b434a17540601ac6e47a6cd84270799de2921c5c9a224ae344fed65b1e3e9e82261989ac86d3240c600cb3b51104abfb1ace04e2cfda426bb3f87930272636a6d1805a539d95eeb102e4317c73e9598add4253759c2ac34c911fabbf664a0c3f97d8162a9db0466ddb77f181ea0ef4d5ec7bdd17991c17c960a3359bffde9f509d7853774b597a331ddd5d49095f6dd2c18ca9bee66c3e32e9658d875ae4226f59fc7422675372b6bb8f63512be4ece8db7321ccb5e39db2a998ccff257d0b6998c066c8f18c48966a4d6d6d2be854ddefd27a8208ca30ec68aabafa3e06db2dc7b397547776f1a7c6da7ce3885b9a2106927ef53d87ad25733e33a045f2c12f793c3ff06c02e781d4df33ea28e420a9c6a2ceb430dd0d221c6c55ddbbb9f6fb6edb7ac6b738ffdeeb18e8e8447733f33bcfc38f869e9f820e4b7588ee7c3c6434001d63da97c7e3fa901f337b311dcd2c3f07eed33c8405a4d3143683b780c94489057926ae448dc30b0c33799710305def6466ddcc02dd42441c8d2518bf8138f2bd576ac64ee39a747965afb97d0dc5484e5b161c549b1bb1d91a1083bc909b255a8fab00be9b6e96b40d083ad9d64cef2d7169a47e77541b0076350053df7db6ef9d7bc775ffbc13b723c2f84c2b16c636e78a323996079a5fd9ca41264b0be688b605fab0766907550c8d672b898ed551ae2a29c1b4ffdd777efc910e8419a04db954af3dc35f26419c891873a533d624fa091b40aaf20b4ace71257c489569026e34bcd2c43093eaa86be7278d02f7c6f98407c79985562d8876e47c1efce7bc3a0a87a24da6436dc58bc1074f5470a30445186eaafb2cee3c8326c4a1dac6b5cafe8b4b77143b3f72a4286f6886b756b2b9ab8e63d9c12dd2d57f5c0055fc95d973359bd0cbc64b3e6d10132ddf2e2e97f27e74105720794855212e036d4ee39194737b9467e7754e5f3aad8dea164c6d64a5a21708b995c91717acb89c47f0f43d1d86ff90806f1abb0aa60c7c1275c6f796a3b358dbd46dad43bea3bcc9c7aeb9552978dba3e96d637417d10f72b9fd878ec4a68f348089d2df13320c22f9db6b8a9af0bc49f5639fe64a0e29e417b278da9fc1d9757b1c5ca2fa86282f0ba0277016c92fc3feaf3a24b1e0ada45522c3c2bb6454ccd2262d9b525cd2d5f3349ee4a4629c34923692521674c8266e8da257108b6b1b4bdabfcc29b556d0ef5e78884cca785d78357e126f75dce3a7077cdabc31f25d1d636935d29eea899d70973fdcc5245caf00de536110bc90c81371bbb4015a26066059781af7a131f805aa0204ba388036134397d359b156435a89004317856801f9f3176a1e665de1b06f77008867f967d3c0d03871c81f24c78e8784f39325fa4eb225fa66d7842423802cc3ff701a2629e686f7ae24c0baa8e2566db79e55d78131f61b035c1fcd32c86ee5fe5da5693c8d85254fa92117ab43612e6b1397bb580734898dd30e7ed53f7ecd7ff4f5c081185319d47b833730af98f21919c3aa4813253d9b16517b440a285e26d11c1b0e7671f9693594405cb6141510cc5a44751d0a249d924052f25ffd4b50fe4aebd359c448af88bab21ec47fdfd88b1af95960bb2bc476a07692f90718ce633a32d192600ca7993737c2699735be107a1b33f9eabfd66a1c50f51fcccbd03744b990800b12186afac1ae0a77a20459a8306df87e995b970bf0a5ad088159970ad07979d8022c5d57d6d3a6da35c320ccf2535fbb10acfc5d52687a3dabe80cd2351f1eea130794dd748ea5959707b9d89d1b0e1c638ceb5f02cc5821cbf247835baa7f80d5a3625a598b775b24fbd8613bb399279037a825b3897db1dc403262c225f054bb57289b1e2ee859fef6d478c6148e5bd2b27df135f0df8ff0340ee7d9bf9f53bdb13f22c23c9776f8ebd214b8e3d21af195b4aac626b5c49c6a5ffb756e99368776b5c5e548cfc50a249ccee9a03a65fbfaa9a769670ee02080a50470a163a4e4ef7de04e6426813a15c1e43a56eeeff36e992a8286c03ee39586cca1c80b0c1f47685e46200f510a06645cacede289b98266b39f2c91691ec2ec67c467170e68985a21e6abb345e9ac6c263a9d85e49fff34ecbbd83d3da489e2b26f4d0387ce2cec0f36b13c38acb0ac8da1c31dcaf7a23e44426600a2ce4875347470ee15a345a092d7acb7c4657443d55170cee8c4d98f503a8651f2fd35bc4fb46a3de719cc368c0680c115a60774f7d33210a9e07dad9450a3cc113ba84b2575e0400e9dd1bed9bd5f90ee29fd47c33c66499b71e3d4028a1d8f6de8fdd98bca0100f1c0655cd9e6bede609db7b1abb1fbb9109878195f3b9eb2c624ef76616719079b0a8e308b929a9b7c6262016c829a63928a6eeb613aade24e3a826477ef4a6e12a78e253e7d3c82f6ef046a9f8fd9af75ae5de932785c385f9ad430ab9e4e16ccb5b22705798ef682823987a61e9d01a475391c83a36d40c84e667c45d1aa1535d835a2f6da4d151881a144ff53cf4d2a28e71681a101554677ab1b56b85b988fdd260f6ed18e7073fa3ecb65d3c77920925d0204503260d70800912e97ee5013a389fd6f7bbb1f998008625f8732e88969fe22d22224f814efa56b0baa56801878c10d4e03a2102b612cbb5cfbdc57cc3a371ec3786ba0ef8e9101a8bb1fa0a8cb70f07e82b40287ec4b5d3721c16941dcd303e905434699e874b939e855a75c8f6fb938ed66a74f3aa6406cfb2ea391db809fe192ede1224bf792e10d03debe02be04aaca38e7366cf746120a594e7745d1370184f7ef28b11725ca34f189885c841cf210bd3f9a5f083b8fe514f012363160a6c0357b0950b6f2fd7b7074bc3e8eb31b03d2620878bef97575915820c653f5a2d062e77305cdf0d8859f3f46402149ffc36404de87131c9e00f200952d588ef441acd6a45aa315bfa6503808fcc195fc7d46add884fdd179fbe15f2c32404274e60d5d932ef66d1908e842e351ec0d89f012e182baa6243651e42bb67acbd4c81951b69bc41b3b7c1ffcfcca90082d65613d88ba000494d85a28313b95397a4c463b05b6d2790fb5da3e182cb417f0541909f4623584095988f5bc41301b9573fa36fb0d34ab5a0ef0b3c34defcf06031f555df0d15eb0806c58132c89b96304bef3a79c29c78b4c1e47e7995a4ce78a08d074f47271cf449359da67f44baea74be0524be8f8bea32b997afcf9b03ed563ed10aaf3ede19f8fe7be9e3fc632b1c36fc68b603876abc58100f83fca8d117df8ddadad7c478fedd28befd69c38c3aa51d9c79ce8cf801f15ca48ad58b9d58121e98d633eb894035c73495d09da21368e7f193d11b5823ebc90b0292f0c0291725974ef2e2e84b482f9d6685bcd4fafceff400924bebb6a3349baa9a53968b9066e22551b2316cc0be85d91b07cd9423c3155cb4531e79aee0557cb7deb73ab91f70475841552733d1b949a2e91464a8a56644b09c19b36e4921400e8c839fae75ab15b08d19f52178f722a8425a2a201d8caefc2e33fbeaca3d3226099184a1fbc83b72dcd887d50ef3b1bf0baf69af9ad4aa2ba84f676b26a03abc82793c44c54f51e26def5d58da333da762059bfd87a65fcf2cc9bdf163ab19a0ef876d0406e5a7b93d58b94e7c7c0212234535398ba6a81eeed28bb1a397b0ddee98ea383449d2526009ccfc84f4d98ea214da8ead67a061696c2566c16e20c3790fb160d9bc7e41cfecda9a10a0a82dc54ca34d18701236f89184dc8569fbf8e2132ddf428756f906079dc97be0770f9c7d369f06df98da8c0345ede447a3df1aca7ee4a0f1d188f266b4a902548928d0e9ced8f5929d3014a3eef89eee2eb3709df3a7a5cc527737ccb6a0b914ad9883994a73bc497e5e140ba88f6d0d6e98c1c90260eaa1a35579eb7e4360d84a068991ecad729f052a4aa711e01365d8a54d5acf0db5b88c074eeaea4e7aadf357a01405bc48ce4e75fe2dd8b4eac03024771785166fc85e90f9a55c989ef62ecf84b34c635ed1e5c5885a8cacab7477f54631cf3db0e4ed74b63ddbdfdb637e583c848356f7f4301667b6212486fb1b2005c61ea2c45e4536e48a8848e1a46e98a04d88481c100027ac575c5619f2e9008085410a555fd3383bb3d8471b0228c9f79564e1892585248d14aa05b224a1a215717bb27b493038b7449d31d5c658682339beb53dd47ada0578f3917fbb9f60ece5437c7f49e837a76397d0147c71eef183ccb82dc5cc5720fadb90467330da251a8ef7d20e0e81f213a98a252385d729eb9164e516855f3565e5460f66232b56eae25051b756c7ef2e84e3774a0bae3a7e071a7da0511ffc6c2c45b162f674123bf358cc57aecfd860ee49d6ac6adfdd13b953150c947f662802f08abba0c61047193673bf36c8c6ae3329ae0fa6ea82dbf8251ad43e0280d373feefb714a0716363b003503f01cfbf3d64f6532b64f5b27af5d30949e3c7fff83c29a4a0bb1d46ed3b23b039ec9999b4d00669cd449eb0d8f79c9d3d44b770a3b100c7b034363e8206cd42ab03c2ef20747646eebe26b88bc2e16d9f4d3a81b51a78e5c287d4af021cf6f24d4e7a2a0a48130a43d6e4680f87ce914f942742e4fd35d4c991e18275c899a981a13028c91888fe507c994e433d586b74d498a99399569e3b0d5c970048685828555e29ea18afb70579eefcf4e0816aad7c34cae72f808bc104e8b03979540f56941a06e686861e8f2d723cc9e1ad5f6dddfa1f1c7c17d187f2a28aae79ad94c696bd23fe697a16b3f4e632e56e6cecad10e3eb864a87eb612995b3c67061f4fa02f574092fb65651834dcea7f1a3c15ddcc3d867888217a23d21734c57f6c6bad13d51ff37899f2c63a0c266a33db74ac393e63b8aea4e20e3dc10d06a210688f9cf5d49e25674bf7458034c53e90ff4a9a802731003d05521d4a73797c2ef3eeecd71529bccbc1fc92522bb3bef504d00910caa4406f38d2edfba4dcf0c3b331a91bcfdba2a86b71dd3a4f469f8151e664f5a2bb61c9df9f40590ce21989790f284e9927d065036fd01a89b449bc3ea22fffac53094904b03d64b091abcd4072e1a53ef1428fbe64a1ab46d5a0c8bffb0d9745ff461d076dd62d0f25b5d8b478fc7859055356336c4684e7e4a089da91dba0b584c6c26576043c74e2172685cbedbf1bb35bbddbeba87d9da4ff0dde990ca955ee56ced23e6c7ef803968a67a41a1b075f21e6b9a44a245652ab8639688acd68a0dcf71d6a2484dcde489020ec12562cbd9c63c89f29df436cbec62a53bb67cf614cd42d4576931f3f84650b66637e58f9197b7962b8ff67bfb795c6dc8a609b8f184687e2441df1bcfbabb4f45bd4b77597f424b8e7a348a4965a7e892354172805e08afdc1381b6591a6da32e7a7b426736fa5cf9ecf9689551e52dd1196261fb9cf8d4db7d042f6ff7b34c986fa2d1ea098b1af2680be8b034529a52413211fd5c4bdd9079c0fe85ad38c752eb9437d72763110764d03b3c84aabb37cf054500eea52423d94bd257600a28ac5fe439f40559add0de28497c5fc2c43f4a990dcb994cec1f835241ac9ebdf0da3338bf00c02d6323cbc869acb46bb6a22e0a7027b4d6d0daa83db50ee8f9b7ec1726444e7c3a934f35e7505b10f58c4f38ca1bd25c6a0e9b10d4bebd6b5be6073c8a783184cd939507f501a24f01e57d40e670fee98c56992a5b041a860bcb64cde83e6aeab53b7ccefde7559531097d439630994e4141810bddb7cce7101022734a209f6ca3d5d33862e9eff33d006ec7d9d801539c614f679c4c888ff6e40700ff9b47cae25f06cbb3511fde8f5e5cd3e8d91a874b8d0e59b172780a248bba74a0ca5bbe4917ffeba1bd3856d4b16416da9a49cf82d6b6d784e1fa8fd7e99eace90c2e96be6db7a6c7db3d43286e64c5caa492af66ec4e68f54248ce3678f18c9ed81d29ead9966e971bdc52c71f5f16decb4983190664da0f7de93c0f811535fbb723875d623cf8b501fe25071d011aff03eb8cbe9b68e361d4a568405108f0e604817cf1853e9cc9b57bbbdd4137826680515052568589107fa84dc79682af20115623ca46b2fa76119a6011d760460b76be4ccb2927555e1405744c67edcc9bd9088112affdd5ff6a5a74cfa454965a695e3995d7c3c10432c91467becdd4709689bbc744ee14d938c0f908d1825b181c8e0262c04feab37f46f32c64b2385020fa73f4f01754f9dd35043a1cded8dbea6e083636883404ac13087f2b7b3c940bd8fe79b9487d505118fbf86bcbb35c9019b93cbfff6bb9ae73abf0973113f2cb22175ebe7b2e700c7a0642e27a634a28ab80366fca27ab6dfd4aa3b52ac9b4ce8869d224d333808711b0b0c284675429831637cb4c7a22d326d8b3ce6e18263071d26b0318366c3e2b0010851e14c4ce3d65941e66d43282473ce550c0b88ab2592f59a65cc0ee87d902b32f209a67a75deac8d1a347c01a7f04bfc511136a39261fc123e7ff257ff2aa1032924581b88f342aa5070f609bc5b452e209aa1a3a904f78b8a6001b833d8de25f428d8f2d0575e1a6180d57ebcb5a9a98a5c0bec56c6852759ff8dbd1e8e0a0a8f10fb34de1c647995ba0da288d26be6df567fe9189d74cb10db0d4b72eaa07ad154943aa2750329e3fe494f1132b19cfe71b2f2263c968ecbad59adec46a7d0fda75ecddccd5b43e8d13eff58bed8ddd1ec2173b705fa56ebe1379e7f45fdae5f8cbc1b1c918811662a896e72e8091b397995bcc8dd6bd03608ce891280d10fd7c8f4dd163afce8bf08ebac5a7fa25b0986b33e35855dff48e874dadf90cf05f92a184959587aeab78ed04e8559c9befb2baa73bcc4937245268af3b97869a784bba7a159a5b10c33346c07377b60342bcbedb57743c033c1dc45209417b2e9c57c37ba68a6600a185bd1f668bcb3c36736db1a0f97738d3467d34b52abf20816302f58c627af22c1f14703e6edfb5d2e5f15ab0a1b84342f07cabc84fac28e614c2e364f79f579534f37ad3d202ff0a658f58617e9727a27e6f9613ff89459e941fe9f9ca0b45990b4ade6a5e405195617a70155966399177616d0bc1bdb81cdc8bfcd5f8d2b95ee11741ad92ce80ea03c02aa07da5da78b22c91a7c3299a757cd12fb0c7ed0ea47950315cc92a953dcb2a9f44461be2fc317ba29834985d398c967b019ad2a59a50068946c12ec2aeee7ee3e6c4fffbee71bb3bf8054c4b44dd678af8a615b2bb84942e687703295dda242a4d86acc6662b49ae4cdcd5ea6e3830c25adfe61842c071705898451fbaee2c5ceff10f5935badad805366d0dd6492f33a74b3c9baefafb9de65599259c207f9954ec1db0b2641899e6b5d768967218e6862804242849375bc7724298dcee79bffd90b29e9b1d6132967116858a333ed5f8b3cec4bac52970a0230eb93667d667b108513fb28686900df5e9c883bb5fc3701fd4b729bdbdae55d2af212bb3b02f5804f91554b844e9e4cc1746dbe7666337bebc897a63b91f1cddf9406a53fee6dd79190629afbc1c6c52fb458bec709b2fc3bc5ca613599813442da9f4d5a2df4d441a7e56084d8128a2132f4d0c421e29969a3cc9f670dd1189fb81e7c06e519f4fe56491d010f8aec6a7277282ef8a23bd084107cad620d33600189d01408ee9725aaf26e439886f3549d5f90ff91023fade75e934d4f75bfecf8bafff57803437c9504bc964b2fdd1bbe3208c2a5aec2ea52a5ced1221343a4683a2bf030b0722c20d59dc29b81c504e87b9c8944e5ff005d336fefa850479d33ff9e6872df62178b824209faebd2cb7d11901a5bd048b138d75e1175d4190f747220f58306d631d888901138e3d0b74f77e783310d9cdc02ed8bdb8037276700ecfd64e1f4cfa19046dd90c8a6ed816047591f553417c6dd43a37838ea0c9d79e89a3688a61937a29396f42e6c0ce60d49d7000f4e2972cabf073e37f8558513e6d5ae0a18581e8b269af23811bd081bb78d86cf00d135c190fa582cdb88270960af5e95cc2d12a57c08ad47a53609b52ac3f6846bf5bb4ffce61dd9559242b58fe0dd2aa8b480fedc026152315b82683628c38b17eac2d9b4f8e13fa3b5ab81db11836298d8d848922feccc0fd5c7873786ce13b851a84d2293163249525c9f503206f56fbdf8f33c7766e1c5149f3fc60f7e0d977cacadd12cad12c304a25f98f5b1ccdade2e3531b8d69f71ad6c58e1dbd9ce85a5f9699ee5440c39efba0ad19010d81141dcd37714ad349d564ae4c61626bc7079916aacbfbe7471ce57aa6b24c583109f0e2225548ed44a2482f4990fdc118cb8ec61d25745ff4685f06cceadba1ee8da5186dc18bc97042f05d0b7c787e3c0936af6360e674fee5a9c7e1b8138afc275d9497ed91ace3a7f1ba8e9c0dbbe4825418bda0af48712b74b1d1eade280f3075619b52841ac1e271e215f5150604520de3046d4f4e19e271b6d4f32da20afdd364e5d8357dfa050e2279a09824c8ee8c21dd8246e70ba921076e61032bbe98a29cd45ae0c39bf4c200906f8e3e6ae59f09cd1b539a137ab3946d1067ac2c1c100e839f11a9431c50007af739938c3fce6ec4d927ff7f5af939ef3d19fe39a9f87675d6ccd0fda1abe84835a3621106390928553d3d7e2aaae31f667111276ef1f75c51aa9af08578ddee740c9c3f42de0b08d7549713e0469747f99a1dfd4f009b8737d75bd5bf93db47822cbe326797b4eed7f6ad5244306c3a0c7a7bdba3960f61c32f68c75117226a82b25c5c2f607d7ad07968458d9e0e3ec892b137cc1de3ae086b1996dcb8db9eec0ad3c68aba44847d2d7537c2581c3d6622c547d394978bd83ecb7adeb35ae63969325997241b7cdd873b1904707f797477f334c3f56c544edd722f172b9721c1e6588a241c72a4cc67ec482e19d9471ee94e400b0a9c809af2d7a001b255d96518fb60ba6360dbd566c5dd5ad8ab00ee53bdd48613609f4956cdae8e13865a3d470ad4f746790cbb68fdfc86febdda4e5a31a4cf495e02e7cb8fc65a0ce57b3776d07ea07faff691d4867a5ac6722effd63a1793564fa6da53ef4eef32471ee9cb1400e63fa7340b8b4b9dc3666d4c28a30830f01da734de47244c09ef67198797af5b55da83999812e76d165f1826c22efbed19519b81c3dfddfe56d12fd84f3fa08841a62dbc067ab3c28036f21021618b5275d715380c914b493ff79bcd24f464ac0c642bb4a4d6402da7d7997d91359445d303993a5b03b235239e7f465705eaa04edc8e8643c79843cb0f4be17d36bbe0501a9b62d479647dc861a26b35a9e530151dad5f1c08bc895de466ea159307698f3b03a7f155059e2124e033e4d33f6ad8b43e5faa938d631f96cc6c98d96ad72ee08887f1a322c78489e288282c2228500b7b6d16288762e6db69f7f3efbd6b172eba79795a3fb8d7ccea68ceb29851d246e132a0ce7dbfb6785fe2b5f25f9ca04583eff68b7b2a9c211b92e526dd04d0d045be9698a702ec5323501d7ba15daa95ae49244ffe701a8640cbc8f93bec4db670207393856971d000394509a2d26afc7372a1907441a42618ee2d02fadd305521a08b88172c99250b09c195aa69ba03534b3a83db90637d15d69428179c2b8782a3aa78cb120dc24f32434be5a8855e4bc7ea0b9506b9ed2131717378a8a2480dbaac0d2c1edee5da846181d6f4ded49a9f320916e55aa8da264b62e6c8da265d237855c29944045ea3210a9b33feeaebe7a287ed86c77ca2ceec5df8d94622f78316bd804517ddd3ed1acad1b48fff44557b3d46f08ab2379349a1130fea8470ccc1a0237077d1636aa779a3bf13c687178f8927b846f17f67adcae0bc2b24a0498dd33f7f0d03" + ], + "rawHeaders": { + "access-control-allow-origin": "*", + "cdn-cache-control": "max-age=300", + "cf-ray": "935777255bcfd7ac-LAX", + "connection": "close", + "content-encoding": "br", + "content-type": "application/json", + "date": "Thu, 24 Apr 2025 17:54:21 GMT", + "server": "cloudflare", + "transfer-encoding": "chunked", + "vary": "Accept-Encoding" + }, + "responseIsBinary": false + } +] diff --git a/src/api/providers/fetchers/__tests__/openrouter.test.ts b/src/api/providers/fetchers/__tests__/openrouter.test.ts new file mode 100644 index 0000000000..c27907904f --- /dev/null +++ b/src/api/providers/fetchers/__tests__/openrouter.test.ts @@ -0,0 +1,72 @@ +// npx jest src/api/providers/fetchers/__tests__/openrouter.test.ts + +import path from "path" + +import { back as nockBack } from "nock" + +import { PROMPT_CACHING_MODELS } from "../../../../shared/api" + +import { getOpenRouterModels } from "../openrouter" + +nockBack.fixtures = path.join(__dirname, "fixtures") +nockBack.setMode("dryrun") + +describe("OpenRouter API", () => { + describe("getOpenRouterModels", () => { + it("fetches models and validates schema", async () => { + const { nockDone } = await nockBack("openrouter-models.json") + + const models = await getOpenRouterModels() + + expect( + Object.entries(models) + .filter(([_, model]) => model.supportsPromptCache) + .map(([id, _]) => id) + .sort(), + ).toEqual(Array.from(PROMPT_CACHING_MODELS).sort()) + + expect( + Object.entries(models) + .filter(([_, model]) => model.supportsComputerUse) + .map(([id, _]) => id) + .sort(), + ).toEqual([ + "anthropic/claude-3.5-sonnet", + "anthropic/claude-3.5-sonnet:beta", + "anthropic/claude-3.7-sonnet", + "anthropic/claude-3.7-sonnet:beta", + "anthropic/claude-3.7-sonnet:thinking", + ]) + + expect(models["anthropic/claude-3.7-sonnet"]).toEqual({ + maxTokens: 8192, + contextWindow: 200000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 3, + outputPrice: 15, + cacheWritesPrice: 3.75, + cacheReadsPrice: 0.3, + description: expect.any(String), + thinking: false, + supportsComputerUse: true, + }) + + expect(models["anthropic/claude-3.7-sonnet:thinking"]).toEqual({ + maxTokens: 128000, + contextWindow: 200000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 3, + outputPrice: 15, + cacheWritesPrice: 3.75, + cacheReadsPrice: 0.3, + description: expect.any(String), + thinking: true, + supportsComputerUse: true, + }) + + nockDone() + }) + }) +}) diff --git a/src/api/providers/fetchers/openrouter.ts b/src/api/providers/fetchers/openrouter.ts new file mode 100644 index 0000000000..9a8eaac464 --- /dev/null +++ b/src/api/providers/fetchers/openrouter.ts @@ -0,0 +1,115 @@ +import axios from "axios" +import { z } from "zod" + +import { ApiHandlerOptions, ModelInfo } from "../../../shared/api" +import { parseApiPrice } from "../../../utils/cost" + +// https://openrouter.ai/api/v1/models +export const openRouterModelSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string().optional(), + context_length: z.number(), + max_completion_tokens: z.number().nullish(), + architecture: z + .object({ + modality: z.string().nullish(), + tokenizer: z.string().nullish(), + }) + .optional(), + pricing: z + .object({ + prompt: z.string().nullish(), + completion: z.string().nullish(), + input_cache_write: z.string().nullish(), + input_cache_read: z.string().nullish(), + }) + .optional(), + top_provider: z + .object({ + max_completion_tokens: z.number().nullish(), + }) + .optional(), +}) + +export type OpenRouterModel = z.infer + +const openRouterModelsResponseSchema = z.object({ + data: z.array(openRouterModelSchema), +}) + +type OpenRouterModelsResponse = z.infer + +export async function getOpenRouterModels(options?: ApiHandlerOptions) { + const models: Record = {} + const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1" + + try { + const response = await axios.get(`${baseURL}/models`) + const result = openRouterModelsResponseSchema.safeParse(response.data) + const rawModels = result.success ? result.data.data : response.data.data + + if (!result.success) { + console.error("OpenRouter models response is invalid", result.error.format()) + } + + for (const rawModel of rawModels) { + const cacheWritesPrice = rawModel.pricing?.input_cache_write + ? parseApiPrice(rawModel.pricing?.input_cache_write) + : undefined + + const cacheReadsPrice = rawModel.pricing?.input_cache_read + ? parseApiPrice(rawModel.pricing?.input_cache_read) + : undefined + + // Disable prompt caching for Gemini models for now. + const supportsPromptCache = !!cacheWritesPrice && !!cacheReadsPrice && !rawModel.id.startsWith("google") + + const modelInfo: ModelInfo = { + maxTokens: rawModel.top_provider?.max_completion_tokens, + contextWindow: rawModel.context_length, + supportsImages: rawModel.architecture?.modality?.includes("image"), + supportsPromptCache, + inputPrice: parseApiPrice(rawModel.pricing?.prompt), + outputPrice: parseApiPrice(rawModel.pricing?.completion), + cacheWritesPrice, + cacheReadsPrice, + description: rawModel.description, + thinking: rawModel.id === "anthropic/claude-3.7-sonnet:thinking", + } + + // Then OpenRouter model definition doesn't give us any hints about computer use, + // so we need to set that manually. + // The ideal `maxTokens` values are model dependent, but we should probably DRY + // this up and use the values defined for the Anthropic providers. + switch (true) { + case rawModel.id.startsWith("anthropic/claude-3.7-sonnet"): + modelInfo.supportsComputerUse = true + modelInfo.maxTokens = rawModel.id === "anthropic/claude-3.7-sonnet:thinking" ? 128_000 : 8192 + break + case rawModel.id.startsWith("anthropic/claude-3.5-sonnet-20240620"): + modelInfo.maxTokens = 8192 + break + case rawModel.id.startsWith("anthropic/claude-3.5-sonnet"): + modelInfo.supportsComputerUse = true + modelInfo.maxTokens = 8192 + break + case rawModel.id.startsWith("anthropic/claude-3-5-haiku"): + case rawModel.id.startsWith("anthropic/claude-3-opus"): + case rawModel.id.startsWith("anthropic/claude-3-haiku"): + modelInfo.maxTokens = 8192 + break + default: + break + } + + models[rawModel.id] = modelInfo + } + } catch (error) { + console.error( + `Error fetching OpenRouter models: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + } + + return models +} diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index ab9897c8b0..4b6a7982ca 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -15,7 +15,9 @@ import { convertToSimpleMessages } from "../transform/simple-format" import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" import { BaseProvider } from "./base-provider" import { XmlMatcher } from "../../utils/xml-matcher" -import { DEEP_SEEK_DEFAULT_TEMPERATURE, DEFAULT_HEADERS, AZURE_AI_INFERENCE_PATH } from "./constants" +import { DEFAULT_HEADERS, DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants" + +export const AZURE_AI_INFERENCE_PATH = "/models/chat/completions" export interface OpenAiHandlerOptions extends ApiHandlerOptions {} diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index c44b2ed74e..fecb1049f3 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -1,16 +1,19 @@ import { Anthropic } from "@anthropic-ai/sdk" import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta" -import axios from "axios" import OpenAI from "openai" -import { ApiHandlerOptions, ModelInfo, openRouterDefaultModelId, openRouterDefaultModelInfo } from "../../shared/api" -import { parseApiPrice } from "../../utils/cost" +import { + ApiHandlerOptions, + openRouterDefaultModelId, + openRouterDefaultModelInfo, + PROMPT_CACHING_MODELS, +} from "../../shared/api" import { convertToOpenAiMessages } from "../transform/openai-format" import { ApiStreamChunk } from "../transform/stream" import { convertToR1Format } from "../transform/r1-format" +import { getModelParams, SingleCompletionHandler } from "../index" import { DEFAULT_HEADERS, DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants" -import { getModelParams, SingleCompletionHandler } from ".." import { BaseProvider } from "./base-provider" const OPENROUTER_DEFAULT_PROVIDER_NAME = "[default]" @@ -62,15 +65,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH systemPrompt: string, messages: Anthropic.Messages.MessageParam[], ): AsyncGenerator { - let { - id: modelId, - maxTokens, - thinking, - temperature, - supportsPromptCache, - topP, - reasoningEffort, - } = this.getModel() + let { id: modelId, maxTokens, thinking, temperature, topP, reasoningEffort, info } = this.getModel() // Convert Anthropic messages to OpenAI format. let openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [ @@ -86,8 +81,8 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH // Prompt caching: https://openrouter.ai/docs/prompt-caching // Now with Gemini support: https://openrouter.ai/docs/features/prompt-caching // Note that we don't check the `ModelInfo` object because it is cached - // in the settings for OpenRouter. - if (this.isPromptCacheSupported(modelId)) { + // in the settings for OpenRouter and the value could be stale. + if (PROMPT_CACHING_MODELS.has(modelId)) { openAiMessages[0] = { role: "system", // @ts-ignore-next-line @@ -191,7 +186,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH let id = modelId ?? openRouterDefaultModelId const info = modelInfo ?? openRouterDefaultModelInfo - const supportsPromptCache = modelInfo?.supportsPromptCache const isDeepSeekR1 = id.startsWith("deepseek/deepseek-r1") || modelId === "perplexity/sonar-reasoning" const defaultTemperature = isDeepSeekR1 ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0 const topP = isDeepSeekR1 ? 0.95 : undefined @@ -200,7 +194,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH id, info, ...getModelParams({ options: this.options, model: info, defaultTemperature }), - supportsPromptCache, topP, } } @@ -227,96 +220,4 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH const completion = response as OpenAI.Chat.ChatCompletion return completion.choices[0]?.message?.content || "" } - - private isPromptCacheSupported(modelId: string) { - return ( - modelId.startsWith("anthropic/claude-3.7-sonnet") || - modelId.startsWith("anthropic/claude-3.5-sonnet") || - modelId.startsWith("anthropic/claude-3-opus") || - modelId.startsWith("anthropic/claude-3-haiku") - ) - } -} - -export async function getOpenRouterModels(options?: ApiHandlerOptions) { - const models: Record = {} - - const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1" - - try { - const response = await axios.get(`${baseURL}/models`) - const rawModels = response.data.data - - for (const rawModel of rawModels) { - const modelInfo: ModelInfo = { - maxTokens: rawModel.top_provider?.max_completion_tokens, - contextWindow: rawModel.context_length, - supportsImages: rawModel.architecture?.modality?.includes("image"), - supportsPromptCache: false, - inputPrice: parseApiPrice(rawModel.pricing?.prompt), - outputPrice: parseApiPrice(rawModel.pricing?.completion), - description: rawModel.description, - thinking: rawModel.id === "anthropic/claude-3.7-sonnet:thinking", - } - - // NOTE: This needs to be synced with api.ts/openrouter default model info. - switch (true) { - case rawModel.id.startsWith("anthropic/claude-3.7-sonnet"): - modelInfo.supportsComputerUse = true - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 3.75 - modelInfo.cacheReadsPrice = 0.3 - modelInfo.maxTokens = rawModel.id === "anthropic/claude-3.7-sonnet:thinking" ? 128_000 : 8192 - break - case rawModel.id.startsWith("anthropic/claude-3.5-sonnet-20240620"): - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 3.75 - modelInfo.cacheReadsPrice = 0.3 - modelInfo.maxTokens = 8192 - break - case rawModel.id.startsWith("anthropic/claude-3.5-sonnet"): - modelInfo.supportsComputerUse = true - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 3.75 - modelInfo.cacheReadsPrice = 0.3 - modelInfo.maxTokens = 8192 - break - case rawModel.id.startsWith("anthropic/claude-3-5-haiku"): - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 1.25 - modelInfo.cacheReadsPrice = 0.1 - modelInfo.maxTokens = 8192 - break - case rawModel.id.startsWith("anthropic/claude-3-opus"): - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 18.75 - modelInfo.cacheReadsPrice = 1.5 - modelInfo.maxTokens = 8192 - break - case rawModel.id.startsWith("anthropic/claude-3-haiku"): - modelInfo.supportsPromptCache = true - modelInfo.cacheWritesPrice = 0.3 - modelInfo.cacheReadsPrice = 0.03 - modelInfo.maxTokens = 8192 - break - /* TODO: uncomment once we confirm it's working - case rawModel.id.startsWith("google/gemini-2.5-pro-preview-03-25"): - case rawModel.id.startsWith("google/gemini-2.0-flash-001"): - case rawModel.id.startsWith("google/gemini-flash-1.5"): - modelInfo.supportsPromptCache = true - break - */ - default: - break - } - - models[rawModel.id] = modelInfo - } - } catch (error) { - console.error( - `Error fetching OpenRouter models: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, - ) - } - - return models } diff --git a/src/api/providers/xai.ts b/src/api/providers/xai.ts index 9da02330e9..6425dd0317 100644 --- a/src/api/providers/xai.ts +++ b/src/api/providers/xai.ts @@ -1,11 +1,13 @@ import { Anthropic } from "@anthropic-ai/sdk" import OpenAI from "openai" -import { ApiHandlerOptions, XAIModelId, ModelInfo, xaiDefaultModelId, xaiModels } from "../../shared/api" + +import { ApiHandlerOptions, XAIModelId, xaiDefaultModelId, xaiModels, REASONING_MODELS } from "../../shared/api" import { ApiStream } from "../transform/stream" import { convertToOpenAiMessages } from "../transform/openai-format" -import { DEFAULT_HEADERS, REASONING_MODELS } from "./constants" + +import { SingleCompletionHandler } from "../index" +import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" -import { SingleCompletionHandler } from ".." const XAI_DEFAULT_TEMPERATURE = 0 diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 44e9f1ce74..a62c1d9410 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -12,7 +12,7 @@ import { GlobalFileNames } from "../../shared/globalFileNames" import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage" import { checkExistKey } from "../../shared/checkExistApiConfig" -import { EXPERIMENT_IDS, experimentDefault, ExperimentId } from "../../shared/experiments" +import { experimentDefault } from "../../shared/experiments" import { Terminal } from "../../integrations/terminal/Terminal" import { openFile, openImage } from "../../integrations/misc/open-file" import { selectImages } from "../../integrations/misc/process-images" @@ -25,7 +25,7 @@ import { playTts, setTtsEnabled, setTtsSpeed, stopTts } from "../../utils/tts" import { singleCompletionHandler } from "../../utils/single-completion-handler" import { searchCommits } from "../../utils/git" import { exportSettings, importSettings } from "../config/importExport" -import { getOpenRouterModels } from "../../api/providers/openrouter" +import { getOpenRouterModels } from "../../api/providers/fetchers/openrouter" import { getGlamaModels } from "../../api/providers/glama" import { getUnboundModels } from "../../api/providers/unbound" import { getRequestyModels } from "../../api/providers/requesty" @@ -85,6 +85,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We // if we hadn't retrieved the latest at this point // (see normalizeApiConfiguration > openrouter). const { apiConfiguration: currentApiConfig } = await provider.getState() + getOpenRouterModels(currentApiConfig).then(async (openRouterModels) => { if (Object.keys(openRouterModels).length > 0) { await provider.writeModelsToCache(GlobalFileNames.openRouterModels, openRouterModels) @@ -101,6 +102,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We "openRouterModelInfo", openRouterModels[apiConfiguration.openRouterModelId], ) + await provider.postStateToWebview() } } diff --git a/src/shared/api.ts b/src/shared/api.ts index 4908b26c3a..c8d20dee2f 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -1,7 +1,4 @@ import { ModelInfo, ProviderName, ProviderSettings } from "../schemas" -import { REASONING_MODELS } from "../api/providers/constants" - -export { REASONING_MODELS } export type { ModelInfo, ProviderName as ApiProvider } @@ -1396,3 +1393,32 @@ export const vscodeLlmModels = { maxInputTokens: number } > + +/** + * Constants + */ + +export const REASONING_MODELS = new Set(["x-ai/grok-3-mini-beta", "grok-3-mini-beta", "grok-3-mini-fast-beta"]) + +export const PROMPT_CACHING_MODELS = new Set([ + "anthropic/claude-3-haiku", + "anthropic/claude-3-haiku:beta", + "anthropic/claude-3-opus", + "anthropic/claude-3-opus:beta", + "anthropic/claude-3-sonnet", + "anthropic/claude-3-sonnet:beta", + "anthropic/claude-3.5-haiku", + "anthropic/claude-3.5-haiku-20241022", + "anthropic/claude-3.5-haiku-20241022:beta", + "anthropic/claude-3.5-haiku:beta", + "anthropic/claude-3.5-sonnet", + "anthropic/claude-3.5-sonnet-20240620", + "anthropic/claude-3.5-sonnet-20240620:beta", + "anthropic/claude-3.5-sonnet:beta", + "anthropic/claude-3.7-sonnet", + "anthropic/claude-3.7-sonnet:beta", + "anthropic/claude-3.7-sonnet:thinking", + // "google/gemini-2.0-flash-001", + // "google/gemini-flash-1.5", + // "google/gemini-flash-1.5-8b", +]) diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index fac2b63844..a1fbf5fab8 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -9,10 +9,9 @@ import { openAiNativeModels, vertexModels, xaiModels, - REASONING_MODELS, } from "@roo/shared/api" -export { REASONING_MODELS } +export { REASONING_MODELS, PROMPT_CACHING_MODELS } from "@roo/shared/api" export const MODELS_BY_PROVIDER: Partial>> = { anthropic: anthropicModels,