From 0ac06b7b7bd8c45737cf8232719d249297a0fc26 Mon Sep 17 00:00:00 2001 From: willtai Date: Tue, 10 Dec 2024 18:02:59 +0000 Subject: [PATCH 1/5] Use json-repair package to fix LLM generated json (#226) * Use json-repair package to fix LLM generated json * Removed redundant repaired_json.strip() * Rename test to test_extractor_llm_unfixable_json * Readded llama-index to dependencies * Removed print * Renamed JSONRepairError to InvalidJSONError * Use cast for repaired_json instead of isinstance * Add InvalidJSONError hyperlink to API docs --- CHANGELOG.md | 7 + docs/source/api.rst | 9 + poetry.lock | 2340 ++++++++--------- pyproject.toml | 1 + .../components/entity_relation_extractor.py | 65 +- .../experimental/pipeline/exceptions.py | 6 + src/neo4j_graphrag/generation/prompts.py | 6 +- src/neo4j_graphrag/llm/mistralai_llm.py | 18 +- .../test_entity_relation_extractor.py | 24 +- 9 files changed, 1233 insertions(+), 1243 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a4f02a7..7254d570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Next +## Added +- Integrated json-repair package to handle and repair invalid JSON generated by LLMs. +- Introduced InvalidJSONError exception for handling cases where JSON repair fails. + +## Changed +- Updated LLM prompts to include stricter instructions for generating valid JSON. + ### Fixed - Added schema functions to the documentation. diff --git a/docs/source/api.rst b/docs/source/api.rst index 6cedc097..68a0884a 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -384,6 +384,8 @@ Errors * :class:`neo4j_graphrag.experimental.pipeline.exceptions.PipelineStatusUpdateError` + * :class:`neo4j_graphrag.experimental.pipeline.exceptions.InvalidJSONError` + Neo4jGraphRagError ================== @@ -509,3 +511,10 @@ PipelineStatusUpdateError .. autoclass:: neo4j_graphrag.experimental.pipeline.exceptions.PipelineStatusUpdateError :show-inheritance: + + +InvalidJSONError +================ + +.. autoclass:: neo4j_graphrag.experimental.pipeline.exceptions.InvalidJSONError + :show-inheritance: diff --git a/poetry.lock b/poetry.lock index 3b0f41ad..e7bf3849 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,124 +1,110 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" -version = "2.4.3" +version = "2.4.4" description = "Happy Eyeballs for asyncio" optional = true python-versions = ">=3.8" files = [ - {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, - {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, + {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, + {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, ] [[package]] name = "aiohttp" -version = "3.10.10" +version = "3.11.10" description = "Async http client/server framework (asyncio)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, - {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, - {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, - {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, - {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, - {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, - {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, - {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, - {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, - {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, - {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, - {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, - {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, - {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cbad88a61fa743c5d283ad501b01c153820734118b65aee2bd7dbb735475ce0d"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80886dac673ceaef499de2f393fc80bb4481a129e6cb29e624a12e3296cc088f"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61b9bae80ed1f338c42f57c16918853dc51775fb5cb61da70d590de14d8b5fb4"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e2e576caec5c6a6b93f41626c9c02fc87cd91538b81a3670b2e04452a63def6"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02c13415b5732fb6ee7ff64583a5e6ed1c57aa68f17d2bda79c04888dfdc2769"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfce37f31f20800a6a6620ce2cdd6737b82e42e06e6e9bd1b36f546feb3c44f"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bbbfff4c679c64e6e23cb213f57cc2c9165c9a65d63717108a644eb5a7398df"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49c7dbbc1a559ae14fc48387a115b7d4bbc84b4a2c3b9299c31696953c2a5219"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68386d78743e6570f054fe7949d6cb37ef2b672b4d3405ce91fafa996f7d9b4d"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9ef405356ba989fb57f84cac66f7b0260772836191ccefbb987f414bcd2979d9"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5d6958671b296febe7f5f859bea581a21c1d05430d1bbdcf2b393599b1cdce77"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:99b7920e7165be5a9e9a3a7f1b680f06f68ff0d0328ff4079e5163990d046767"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0dc49f42422163efb7e6f1df2636fe3db72713f6cd94688e339dbe33fe06d61d"}, + {file = "aiohttp-3.11.10-cp310-cp310-win32.whl", hash = "sha256:40d1c7a7f750b5648642586ba7206999650208dbe5afbcc5284bcec6579c9b91"}, + {file = "aiohttp-3.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:68ff6f48b51bd78ea92b31079817aff539f6c8fc80b6b8d6ca347d7c02384e33"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:77c4aa15a89847b9891abf97f3d4048f3c2d667e00f8a623c89ad2dccee6771b"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:909af95a72cedbefe5596f0bdf3055740f96c1a4baa0dd11fd74ca4de0b4e3f1"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:386fbe79863eb564e9f3615b959e28b222259da0c48fd1be5929ac838bc65683"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3de34936eb1a647aa919655ff8d38b618e9f6b7f250cc19a57a4bf7fd2062b6d"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c9527819b29cd2b9f52033e7fb9ff08073df49b4799c89cb5754624ecd98299"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a96e3e03300b41f261bbfd40dfdbf1c301e87eab7cd61c054b1f2e7c89b9e8"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f5635f7b74bcd4f6f72fcd85bea2154b323a9f05226a80bc7398d0c90763b0"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03b6002e20938fc6ee0918c81d9e776bebccc84690e2b03ed132331cca065ee5"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6362cc6c23c08d18ddbf0e8c4d5159b5df74fea1a5278ff4f2c79aed3f4e9f46"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3691ed7726fef54e928fe26344d930c0c8575bc968c3e239c2e1a04bd8cf7838"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31d5093d3acd02b31c649d3a69bb072d539d4c7659b87caa4f6d2bcf57c2fa2b"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8b3cf2dc0f0690a33f2d2b2cb15db87a65f1c609f53c37e226f84edb08d10f52"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbbaea811a2bba171197b08eea288b9402faa2bab2ba0858eecdd0a4105753a3"}, + {file = "aiohttp-3.11.10-cp311-cp311-win32.whl", hash = "sha256:4b2c7ac59c5698a7a8207ba72d9e9c15b0fc484a560be0788b31312c2c5504e4"}, + {file = "aiohttp-3.11.10-cp311-cp311-win_amd64.whl", hash = "sha256:974d3a2cce5fcfa32f06b13ccc8f20c6ad9c51802bb7f829eae8a1845c4019ec"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b78f053a7ecfc35f0451d961dacdc671f4bcbc2f58241a7c820e9d82559844cf"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab7485222db0959a87fbe8125e233b5a6f01f4400785b36e8a7878170d8c3138"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cf14627232dfa8730453752e9cdc210966490992234d77ff90bc8dc0dce361d5"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076bc454a7e6fd646bc82ea7f98296be0b1219b5e3ef8a488afbdd8e81fbac50"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:482cafb7dc886bebeb6c9ba7925e03591a62ab34298ee70d3dd47ba966370d2c"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf3d1a519a324af764a46da4115bdbd566b3c73fb793ffb97f9111dbc684fc4d"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24213ba85a419103e641e55c27dc7ff03536c4873470c2478cce3311ba1eee7b"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b99acd4730ad1b196bfb03ee0803e4adac371ae8efa7e1cbc820200fc5ded109"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14cdb5a9570be5a04eec2ace174a48ae85833c2aadc86de68f55541f66ce42ab"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7e97d622cb083e86f18317282084bc9fbf261801b0192c34fe4b1febd9f7ae69"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:012f176945af138abc10c4a48743327a92b4ca9adc7a0e078077cdb5dbab7be0"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44224d815853962f48fe124748227773acd9686eba6dc102578defd6fc99e8d9"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c87bf31b7fdab94ae3adbe4a48e711bfc5f89d21cf4c197e75561def39e223bc"}, + {file = "aiohttp-3.11.10-cp312-cp312-win32.whl", hash = "sha256:06a8e2ee1cbac16fe61e51e0b0c269400e781b13bcfc33f5425912391a542985"}, + {file = "aiohttp-3.11.10-cp312-cp312-win_amd64.whl", hash = "sha256:be2b516f56ea883a3e14dda17059716593526e10fb6303189aaf5503937db408"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8cc5203b817b748adccb07f36390feb730b1bc5f56683445bfe924fc270b8816"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ef359ebc6949e3a34c65ce20230fae70920714367c63afd80ea0c2702902ccf"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9bca390cb247dbfaec3c664326e034ef23882c3f3bfa5fbf0b56cad0320aaca5"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811f23b3351ca532af598405db1093f018edf81368e689d1b508c57dcc6b6a32"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddf5f7d877615f6a1e75971bfa5ac88609af3b74796ff3e06879e8422729fd01"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ab29b8a0beb6f8eaf1e5049252cfe74adbaafd39ba91e10f18caeb0e99ffb34"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c49a76c1038c2dd116fa443eba26bbb8e6c37e924e2513574856de3b6516be99"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f3dc0e330575f5b134918976a645e79adf333c0a1439dcf6899a80776c9ab39"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:efb15a17a12497685304b2d976cb4939e55137df7b09fa53f1b6a023f01fcb4e"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:db1d0b28fcb7f1d35600150c3e4b490775251dea70f894bf15c678fdd84eda6a"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:15fccaf62a4889527539ecb86834084ecf6e9ea70588efde86e8bc775e0e7542"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:593c114a2221444f30749cc5e5f4012488f56bd14de2af44fe23e1e9894a9c60"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7852bbcb4d0d2f0c4d583f40c3bc750ee033265d80598d0f9cb6f372baa6b836"}, + {file = "aiohttp-3.11.10-cp313-cp313-win32.whl", hash = "sha256:65e55ca7debae8faaffee0ebb4b47a51b4075f01e9b641c31e554fd376595c6c"}, + {file = "aiohttp-3.11.10-cp313-cp313-win_amd64.whl", hash = "sha256:beb39a6d60a709ae3fb3516a1581777e7e8b76933bb88c8f4420d875bb0267c6"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0580f2e12de2138f34debcd5d88894786453a76e98febaf3e8fe5db62d01c9bf"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a55d2ad345684e7c3dd2c20d2f9572e9e1d5446d57200ff630e6ede7612e307f"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04814571cb72d65a6899db6099e377ed00710bf2e3eafd2985166f2918beaf59"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e44a9a3c053b90c6f09b1bb4edd880959f5328cf63052503f892c41ea786d99f"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:502a1464ccbc800b4b1995b302efaf426e8763fadf185e933c2931df7db9a199"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:613e5169f8ae77b1933e42e418a95931fb4867b2991fc311430b15901ed67079"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cca22a61b7fe45da8fc73c3443150c3608750bbe27641fc7558ec5117b27fdf"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86a5dfcc39309470bd7b68c591d84056d195428d5d2e0b5ccadfbaf25b026ebc"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:77ae58586930ee6b2b6f696c82cf8e78c8016ec4795c53e36718365f6959dc82"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:78153314f26d5abef3239b4a9af20c229c6f3ecb97d4c1c01b22c4f87669820c"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:98283b94cc0e11c73acaf1c9698dea80c830ca476492c0fe2622bd931f34b487"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:53bf2097e05c2accc166c142a2090e4c6fd86581bde3fd9b2d3f9e93dda66ac1"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5532f0441fc09c119e1dca18fbc0687e64fbeb45aa4d6a87211ceaee50a74c4"}, + {file = "aiohttp-3.11.10-cp39-cp39-win32.whl", hash = "sha256:47ad15a65fb41c570cd0ad9a9ff8012489e68176e7207ec7b82a0940dddfd8be"}, + {file = "aiohttp-3.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:c6b9e6d7e41656d78e37ce754813fa44b455c3d0d0dced2a047def7dc5570b74"}, + {file = "aiohttp-3.11.10.tar.gz", hash = "sha256:b1fc6b45010a8d0ff9e88f9f2418c6fd408c99c211257334aff41597ebece42e"}, ] [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.12.0,<2.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -186,35 +172,35 @@ vertex = ["google-auth (>=2,<3)"] [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = true python-versions = ">=3.9" files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] @@ -527,19 +513,20 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "cohere" -version = "5.11.1" +version = "5.13.3" description = "" optional = true -python-versions = "<4.0,>=3.8" +python-versions = "<4.0,>=3.9" files = [ - {file = "cohere-5.11.1-py3-none-any.whl", hash = "sha256:117c718bfbc7637cf22c1025e8e2bf820ebeef51f7fbb2b9d74f3e9c0a9c6c25"}, - {file = "cohere-5.11.1.tar.gz", hash = "sha256:821e20593def7796d314be9bcba87e9ecf69dc6ef17172f842447275f8679d0f"}, + {file = "cohere-5.13.3-py3-none-any.whl", hash = "sha256:076c88fdd3d670b6577eb8e813a9072bf18b59648d4092c6f0263af3c27bf81f"}, + {file = "cohere-5.13.3.tar.gz", hash = "sha256:70d87e0d5ce48aaee5ba70ead5efbade226cb2a4b11bfcfb676f6a2db3642819"}, ] [package.dependencies] fastavro = ">=1.9.4,<2.0.0" httpx = ">=0.21.2" httpx-sse = "0.4.0" +numpy = ">=1.26,<2.0" parameterized = ">=0.9.0,<0.10.0" pydantic = ">=1.9.2" pydantic-core = ">=2.18.2,<3.0.0" @@ -564,73 +551,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.4" +version = "7.6.9" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, - {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, - {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, - {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, - {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, - {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, - {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, - {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, - {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, - {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, - {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, - {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, - {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, - {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, - {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, - {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073"}, + {file = "coverage-7.6.9-cp310-cp310-win32.whl", hash = "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198"}, + {file = "coverage-7.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3"}, + {file = "coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0"}, + {file = "coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f"}, + {file = "coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692"}, + {file = "coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb"}, + {file = "coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba"}, + {file = "coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9"}, + {file = "coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b"}, + {file = "coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678"}, + {file = "coverage-7.6.9-cp39-cp39-win32.whl", hash = "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6"}, + {file = "coverage-7.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4"}, + {file = "coverage-7.6.9-pp39.pp310-none-any.whl", hash = "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b"}, + {file = "coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d"}, ] [package.extras] @@ -702,20 +689,20 @@ typing-inspect = ">=0.4.0,<1" [[package]] name = "deprecated" -version = "1.2.14" +version = "1.2.15" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, + {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, + {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, ] [package.dependencies] wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "setuptools", "sphinx (<2)", "tox"] [[package]] name = "dirtyjson" @@ -1004,13 +991,13 @@ tqdm = ["tqdm"] [[package]] name = "google-api-core" -version = "2.21.0" +version = "2.24.0" description = "Google API client core library" optional = true python-versions = ">=3.7" files = [ - {file = "google_api_core-2.21.0-py3-none-any.whl", hash = "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d"}, - {file = "google_api_core-2.21.0.tar.gz", hash = "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81"}, + {file = "google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9"}, + {file = "google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf"}, ] [package.dependencies] @@ -1024,7 +1011,10 @@ grpcio-status = [ {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, ] -proto-plus = ">=1.22.3,<2.0.0dev" +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, +] protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" @@ -1036,13 +1026,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.35.0" +version = "2.36.0" description = "Google Authentication Library" optional = true python-versions = ">=3.7" files = [ - {file = "google_auth-2.35.0-py2.py3-none-any.whl", hash = "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f"}, - {file = "google_auth-2.35.0.tar.gz", hash = "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a"}, + {file = "google_auth-2.36.0-py2.py3-none-any.whl", hash = "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb"}, + {file = "google_auth-2.36.0.tar.gz", hash = "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1"}, ] [package.dependencies] @@ -1059,13 +1049,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-cloud-aiplatform" -version = "1.70.0" +version = "1.74.0" description = "Vertex AI API client library" optional = true python-versions = ">=3.8" files = [ - {file = "google-cloud-aiplatform-1.70.0.tar.gz", hash = "sha256:e8edef6dbc7911380d0ea55c47544e799f62b891cb1a83b504ca1c09fff9884b"}, - {file = "google_cloud_aiplatform-1.70.0-py2.py3-none-any.whl", hash = "sha256:690e6041f03d3aa85102ac3f316c958d6f43a99aefb7fb3f8938dee56d08abd9"}, + {file = "google_cloud_aiplatform-1.74.0-py2.py3-none-any.whl", hash = "sha256:7f37a835e543a4cb4b62505928b983e307c5fee6d949f831cd3804f03c753d87"}, + {file = "google_cloud_aiplatform-1.74.0.tar.gz", hash = "sha256:2202e4e0cbbd2db02835737a1ae9a51ad7bf75c8ed130a3fdbcfced33525e3f0"}, ] [package.dependencies] @@ -1083,13 +1073,13 @@ shapely = "<3.0.0dev" [package.extras] autologging = ["mlflow (>=1.27.0,<=2.16.0)"] -cloud-profiler = ["tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] +cloud-profiler = ["tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] datasets = ["pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)"] endpoint = ["requests (>=2.28.1)"] -evaluation = ["pandas (>=1.0.0,<2.2.0)", "tqdm (>=4.23.0)"] -full = ["docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.114.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.16.0)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "requests (>=2.28.1)", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)"] -langchain = ["langchain (>=0.1.16,<0.3)", "langchain-core (<0.3)", "langchain-google-vertexai (<2)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "orjson (<=3.10.6)", "tenacity (<=8.3)"] -langchain-testing = ["absl-py", "cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "langchain (>=0.1.16,<0.3)", "langchain-core (<0.3)", "langchain-google-vertexai (<2)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "orjson (<=3.10.6)", "pydantic (>=2.6.3,<3)", "pytest-xdist", "tenacity (<=8.3)"] +evaluation = ["pandas (>=1.0.0)", "tqdm (>=4.23.0)"] +full = ["docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.114.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.16.0)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "requests (>=2.28.1)", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)"] +langchain = ["langchain (>=0.1.16,<0.4)", "langchain-core (<0.4)", "langchain-google-vertexai (<3)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)"] +langchain-testing = ["absl-py", "cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "langchain (>=0.1.16,<0.4)", "langchain-core (<0.4)", "langchain-google-vertexai (<3)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.6.3,<2.10)", "pytest-xdist"] lit = ["explainable-ai-sdk (>=1.0.0)", "lit-nlp (==0.4.0)", "pandas (>=1.0.0)", "tensorflow (>=2.3.0,<3.0.0dev)"] metadata = ["numpy (>=1.15.0)", "pandas (>=1.0.0)"] pipelines = ["pyyaml (>=5.3.1,<7)"] @@ -1097,22 +1087,22 @@ prediction = ["docker (>=5.0.3)", "fastapi (>=0.71.0,<=0.114.0)", "httpx (>=0.23 private-endpoints = ["requests (>=2.28.1)", "urllib3 (>=1.21.1,<1.27)"] ray = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0)", "pyarrow (>=6.0.1)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "setuptools (<70.0.0)"] ray-testing = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0)", "pyarrow (>=6.0.1)", "pytest-xdist", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "ray[train]", "scikit-learn", "setuptools (<70.0.0)", "tensorflow", "torch (>=2.0.0,<2.1.0)", "xgboost", "xgboost-ray"] -reasoningengine = ["cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.6.3,<3)"] -tensorboard = ["tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] -testing = ["bigframes", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.114.0)", "google-api-core (>=2.11,<3.0.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "grpcio-testing", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "ipython", "kfp (>=2.6.0,<3.0.0)", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.16.0)", "nltk", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pytest-asyncio", "pytest-xdist", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "requests (>=2.28.1)", "requests-toolbelt (<1.0.0)", "scikit-learn", "sentencepiece (>=0.2.0)", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (==2.13.0)", "tensorflow (==2.16.1)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "torch (>=2.0.0,<2.1.0)", "torch (>=2.2.0)", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)", "xgboost"] +reasoningengine = ["cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.6.3,<2.10)"] +tensorboard = ["tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] +testing = ["aiohttp", "bigframes", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.114.0)", "google-api-core (>=2.11,<3.0.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "grpcio-testing", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "ipython", "kfp (>=2.6.0,<3.0.0)", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.16.0)", "nltk", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pytest-asyncio", "pytest-xdist", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || >=2.33.dev0,<=2.33.0)", "ray[default] (>=2.5,<=2.33.0)", "requests (>=2.28.1)", "requests-toolbelt (<1.0.0)", "scikit-learn", "sentencepiece (>=0.2.0)", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (==2.13.0)", "tensorflow (==2.16.1)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "torch (>=2.0.0,<2.1.0)", "torch (>=2.2.0)", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)", "xgboost"] tokenization = ["sentencepiece (>=0.2.0)"] vizier = ["google-vizier (>=0.1.6)"] xai = ["tensorflow (>=2.3.0,<3.0.0dev)"] [[package]] name = "google-cloud-bigquery" -version = "3.26.0" +version = "3.27.0" description = "Google BigQuery API client library" optional = true python-versions = ">=3.7" files = [ - {file = "google_cloud_bigquery-3.26.0-py2.py3-none-any.whl", hash = "sha256:e0e9ad28afa67a18696e624cbccab284bf2c0a3f6eeb9eeb0426c69b943793a8"}, - {file = "google_cloud_bigquery-3.26.0.tar.gz", hash = "sha256:edbdc788beea659e04c0af7fe4dcd6d9155344b98951a0d5055bd2f15da4ba23"}, + {file = "google_cloud_bigquery-3.27.0-py2.py3-none-any.whl", hash = "sha256:b53b0431e5ba362976a4cd8acce72194b4116cdf8115030c7b339b884603fcc3"}, + {file = "google_cloud_bigquery-3.27.0.tar.gz", hash = "sha256:379c524054d7b090fa56d0c22662cc6e6458a6229b6754c0e7177e3a73421d2c"}, ] [package.dependencies] @@ -1155,31 +1145,34 @@ grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-resource-manager" -version = "1.12.5" +version = "1.13.1" description = "Google Cloud Resource Manager API client library" optional = true python-versions = ">=3.7" files = [ - {file = "google_cloud_resource_manager-1.12.5-py2.py3-none-any.whl", hash = "sha256:2708a718b45c79464b7b21559c701b5c92e6b0b1ab2146d0a256277a623dc175"}, - {file = "google_cloud_resource_manager-1.12.5.tar.gz", hash = "sha256:b7af4254401ed4efa3aba3a929cb3ddb803fa6baf91a78485e45583597de5891"}, + {file = "google_cloud_resource_manager-1.13.1-py2.py3-none-any.whl", hash = "sha256:abdc7d443ab6c0763b8ed49ab59203e223f14c683df69e3748d5eb2237475f5f"}, + {file = "google_cloud_resource_manager-1.13.1.tar.gz", hash = "sha256:bee9f2fb1d856731182b7cc05980d216aae848947ccdadf2848a2c64ccd6bbea"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, +] protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "google-cloud-storage" -version = "2.18.2" +version = "2.19.0" description = "Google Cloud Storage API client library" optional = true python-versions = ">=3.7" files = [ - {file = "google_cloud_storage-2.18.2-py2.py3-none-any.whl", hash = "sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166"}, - {file = "google_cloud_storage-2.18.2.tar.gz", hash = "sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99"}, + {file = "google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba"}, + {file = "google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"}, ] [package.dependencies] @@ -1253,13 +1246,13 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.65.0" +version = "1.66.0" description = "Common protobufs used in Google APIs" optional = true python-versions = ">=3.7" files = [ - {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, - {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, + {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, + {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, ] [package.dependencies] @@ -1373,168 +1366,168 @@ protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4 [[package]] name = "grpcio" -version = "1.67.0" +version = "1.68.1" description = "HTTP/2-based RPC framework" optional = true python-versions = ">=3.8" files = [ - {file = "grpcio-1.67.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:bd79929b3bb96b54df1296cd3bf4d2b770bd1df6c2bdf549b49bab286b925cdc"}, - {file = "grpcio-1.67.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:16724ffc956ea42967f5758c2f043faef43cb7e48a51948ab593570570d1e68b"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:2b7183c80b602b0ad816315d66f2fb7887614ead950416d60913a9a71c12560d"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efe32b45dd6d118f5ea2e5deaed417d8a14976325c93812dd831908522b402c9"}, - {file = "grpcio-1.67.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe89295219b9c9e47780a0f1c75ca44211e706d1c598242249fe717af3385ec8"}, - {file = "grpcio-1.67.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa8d025fae1595a207b4e47c2e087cb88d47008494db258ac561c00877d4c8f8"}, - {file = "grpcio-1.67.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f95e15db43e75a534420e04822df91f645664bf4ad21dfaad7d51773c80e6bb4"}, - {file = "grpcio-1.67.0-cp310-cp310-win32.whl", hash = "sha256:a6b9a5c18863fd4b6624a42e2712103fb0f57799a3b29651c0e5b8119a519d65"}, - {file = "grpcio-1.67.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6eb68493a05d38b426604e1dc93bfc0137c4157f7ab4fac5771fd9a104bbaa6"}, - {file = "grpcio-1.67.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:e91d154689639932305b6ea6f45c6e46bb51ecc8ea77c10ef25aa77f75443ad4"}, - {file = "grpcio-1.67.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb204a742997277da678611a809a8409657b1398aaeebf73b3d9563b7d154c13"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:ae6de510f670137e755eb2a74b04d1041e7210af2444103c8c95f193340d17ee"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74b900566bdf68241118f2918d312d3bf554b2ce0b12b90178091ea7d0a17b3d"}, - {file = "grpcio-1.67.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4e95e43447a02aa603abcc6b5e727d093d161a869c83b073f50b9390ecf0fa8"}, - {file = "grpcio-1.67.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0bb94e66cd8f0baf29bd3184b6aa09aeb1a660f9ec3d85da615c5003154bc2bf"}, - {file = "grpcio-1.67.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:82e5bd4b67b17c8c597273663794a6a46a45e44165b960517fe6d8a2f7f16d23"}, - {file = "grpcio-1.67.0-cp311-cp311-win32.whl", hash = "sha256:7fc1d2b9fd549264ae585026b266ac2db53735510a207381be509c315b4af4e8"}, - {file = "grpcio-1.67.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac11ecb34a86b831239cc38245403a8de25037b448464f95c3315819e7519772"}, - {file = "grpcio-1.67.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:227316b5631260e0bef8a3ce04fa7db4cc81756fea1258b007950b6efc90c05d"}, - {file = "grpcio-1.67.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d90cfdafcf4b45a7a076e3e2a58e7bc3d59c698c4f6470b0bb13a4d869cf2273"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:77196216d5dd6f99af1c51e235af2dd339159f657280e65ce7e12c1a8feffd1d"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15c05a26a0f7047f720da41dc49406b395c1470eef44ff7e2c506a47ac2c0591"}, - {file = "grpcio-1.67.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3840994689cc8cbb73d60485c594424ad8adb56c71a30d8948d6453083624b52"}, - {file = "grpcio-1.67.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5a1e03c3102b6451028d5dc9f8591131d6ab3c8a0e023d94c28cb930ed4b5f81"}, - {file = "grpcio-1.67.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:682968427a63d898759474e3b3178d42546e878fdce034fd7474ef75143b64e3"}, - {file = "grpcio-1.67.0-cp312-cp312-win32.whl", hash = "sha256:d01793653248f49cf47e5695e0a79805b1d9d4eacef85b310118ba1dfcd1b955"}, - {file = "grpcio-1.67.0-cp312-cp312-win_amd64.whl", hash = "sha256:985b2686f786f3e20326c4367eebdaed3e7aa65848260ff0c6644f817042cb15"}, - {file = "grpcio-1.67.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:8c9a35b8bc50db35ab8e3e02a4f2a35cfba46c8705c3911c34ce343bd777813a"}, - {file = "grpcio-1.67.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:42199e704095b62688998c2d84c89e59a26a7d5d32eed86d43dc90e7a3bd04aa"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:c4c425f440fb81f8d0237c07b9322fc0fb6ee2b29fbef5f62a322ff8fcce240d"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:323741b6699cd2b04a71cb38f502db98f90532e8a40cb675393d248126a268af"}, - {file = "grpcio-1.67.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:662c8e105c5e5cee0317d500eb186ed7a93229586e431c1bf0c9236c2407352c"}, - {file = "grpcio-1.67.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f6bd2ab135c64a4d1e9e44679a616c9bc944547357c830fafea5c3caa3de5153"}, - {file = "grpcio-1.67.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:2f55c1e0e2ae9bdd23b3c63459ee4c06d223b68aeb1961d83c48fb63dc29bc03"}, - {file = "grpcio-1.67.0-cp313-cp313-win32.whl", hash = "sha256:fd6bc27861e460fe28e94226e3673d46e294ca4673d46b224428d197c5935e69"}, - {file = "grpcio-1.67.0-cp313-cp313-win_amd64.whl", hash = "sha256:cf51d28063338608cd8d3cd64677e922134837902b70ce00dad7f116e3998210"}, - {file = "grpcio-1.67.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:7f200aca719c1c5dc72ab68be3479b9dafccdf03df530d137632c534bb6f1ee3"}, - {file = "grpcio-1.67.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0892dd200ece4822d72dd0952f7112c542a487fc48fe77568deaaa399c1e717d"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f4d613fbf868b2e2444f490d18af472ccb47660ea3df52f068c9c8801e1f3e85"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c69bf11894cad9da00047f46584d5758d6ebc9b5950c0dc96fec7e0bce5cde9"}, - {file = "grpcio-1.67.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9bca3ca0c5e74dea44bf57d27e15a3a3996ce7e5780d61b7c72386356d231db"}, - {file = "grpcio-1.67.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:014dfc020e28a0d9be7e93a91f85ff9f4a87158b7df9952fe23cc42d29d31e1e"}, - {file = "grpcio-1.67.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d4ea4509d42c6797539e9ec7496c15473177ce9abc89bc5c71e7abe50fc25737"}, - {file = "grpcio-1.67.0-cp38-cp38-win32.whl", hash = "sha256:9d75641a2fca9ae1ae86454fd25d4c298ea8cc195dbc962852234d54a07060ad"}, - {file = "grpcio-1.67.0-cp38-cp38-win_amd64.whl", hash = "sha256:cff8e54d6a463883cda2fab94d2062aad2f5edd7f06ae3ed030f2a74756db365"}, - {file = "grpcio-1.67.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:62492bd534979e6d7127b8a6b29093161a742dee3875873e01964049d5250a74"}, - {file = "grpcio-1.67.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eef1dce9d1a46119fd09f9a992cf6ab9d9178b696382439446ca5f399d7b96fe"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f623c57a5321461c84498a99dddf9d13dac0e40ee056d884d6ec4ebcab647a78"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54d16383044e681f8beb50f905249e4e7261dd169d4aaf6e52eab67b01cbbbe2"}, - {file = "grpcio-1.67.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2a44e572fb762c668e4812156b81835f7aba8a721b027e2d4bb29fb50ff4d33"}, - {file = "grpcio-1.67.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:391df8b0faac84d42f5b8dfc65f5152c48ed914e13c522fd05f2aca211f8bfad"}, - {file = "grpcio-1.67.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfd9306511fdfc623a1ba1dc3bc07fbd24e6cfbe3c28b4d1e05177baa2f99617"}, - {file = "grpcio-1.67.0-cp39-cp39-win32.whl", hash = "sha256:30d47dbacfd20cbd0c8be9bfa52fdb833b395d4ec32fe5cff7220afc05d08571"}, - {file = "grpcio-1.67.0-cp39-cp39-win_amd64.whl", hash = "sha256:f55f077685f61f0fbd06ea355142b71e47e4a26d2d678b3ba27248abfe67163a"}, - {file = "grpcio-1.67.0.tar.gz", hash = "sha256:e090b2553e0da1c875449c8e75073dd4415dd71c9bde6a406240fdf4c0ee467c"}, + {file = "grpcio-1.68.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:d35740e3f45f60f3c37b1e6f2f4702c23867b9ce21c6410254c9c682237da68d"}, + {file = "grpcio-1.68.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d99abcd61760ebb34bdff37e5a3ba333c5cc09feda8c1ad42547bea0416ada78"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:f8261fa2a5f679abeb2a0a93ad056d765cdca1c47745eda3f2d87f874ff4b8c9"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0feb02205a27caca128627bd1df4ee7212db051019a9afa76f4bb6a1a80ca95e"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:919d7f18f63bcad3a0f81146188e90274fde800a94e35d42ffe9eadf6a9a6330"}, + {file = "grpcio-1.68.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:963cc8d7d79b12c56008aabd8b457f400952dbea8997dd185f155e2f228db079"}, + {file = "grpcio-1.68.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ccf2ebd2de2d6661e2520dae293298a3803a98ebfc099275f113ce1f6c2a80f1"}, + {file = "grpcio-1.68.1-cp310-cp310-win32.whl", hash = "sha256:2cc1fd04af8399971bcd4f43bd98c22d01029ea2e56e69c34daf2bf8470e47f5"}, + {file = "grpcio-1.68.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2e743e51cb964b4975de572aa8fb95b633f496f9fcb5e257893df3be854746"}, + {file = "grpcio-1.68.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c"}, + {file = "grpcio-1.68.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600"}, + {file = "grpcio-1.68.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe"}, + {file = "grpcio-1.68.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0"}, + {file = "grpcio-1.68.1-cp311-cp311-win32.whl", hash = "sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9"}, + {file = "grpcio-1.68.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2"}, + {file = "grpcio-1.68.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:8829924fffb25386995a31998ccbbeaa7367223e647e0122043dfc485a87c666"}, + {file = "grpcio-1.68.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3aed6544e4d523cd6b3119b0916cef3d15ef2da51e088211e4d1eb91a6c7f4f1"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:4efac5481c696d5cb124ff1c119a78bddbfdd13fc499e3bc0ca81e95fc573684"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ab2d912ca39c51f46baf2a0d92aa265aa96b2443266fc50d234fa88bf877d8e"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c87ce2a97434dffe7327a4071839ab8e8bffd0054cc74cbe971fba98aedd60"}, + {file = "grpcio-1.68.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e4842e4872ae4ae0f5497bf60a0498fa778c192cc7a9e87877abd2814aca9475"}, + {file = "grpcio-1.68.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:255b1635b0ed81e9f91da4fcc8d43b7ea5520090b9a9ad9340d147066d1d3613"}, + {file = "grpcio-1.68.1-cp312-cp312-win32.whl", hash = "sha256:7dfc914cc31c906297b30463dde0b9be48e36939575eaf2a0a22a8096e69afe5"}, + {file = "grpcio-1.68.1-cp312-cp312-win_amd64.whl", hash = "sha256:a0c8ddabef9c8f41617f213e527254c41e8b96ea9d387c632af878d05db9229c"}, + {file = "grpcio-1.68.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:a47faedc9ea2e7a3b6569795c040aae5895a19dde0c728a48d3c5d7995fda385"}, + {file = "grpcio-1.68.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:390eee4225a661c5cd133c09f5da1ee3c84498dc265fd292a6912b65c421c78c"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:66a24f3d45c33550703f0abb8b656515b0ab777970fa275693a2f6dc8e35f1c1"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c08079b4934b0bf0a8847f42c197b1d12cba6495a3d43febd7e99ecd1cdc8d54"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8720c25cd9ac25dd04ee02b69256d0ce35bf8a0f29e20577427355272230965a"}, + {file = "grpcio-1.68.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:04cfd68bf4f38f5bb959ee2361a7546916bd9a50f78617a346b3aeb2b42e2161"}, + {file = "grpcio-1.68.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c28848761a6520c5c6071d2904a18d339a796ebe6b800adc8b3f474c5ce3c3ad"}, + {file = "grpcio-1.68.1-cp313-cp313-win32.whl", hash = "sha256:77d65165fc35cff6e954e7fd4229e05ec76102d4406d4576528d3a3635fc6172"}, + {file = "grpcio-1.68.1-cp313-cp313-win_amd64.whl", hash = "sha256:a8040f85dcb9830d8bbb033ae66d272614cec6faceee88d37a88a9bd1a7a704e"}, + {file = "grpcio-1.68.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:eeb38ff04ab6e5756a2aef6ad8d94e89bb4a51ef96e20f45c44ba190fa0bcaad"}, + {file = "grpcio-1.68.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a3869a6661ec8f81d93f4597da50336718bde9eb13267a699ac7e0a1d6d0bea"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2c4cec6177bf325eb6faa6bd834d2ff6aa8bb3b29012cceb4937b86f8b74323c"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12941d533f3cd45d46f202e3667be8ebf6bcb3573629c7ec12c3e211d99cfccf"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80af6f1e69c5e68a2be529990684abdd31ed6622e988bf18850075c81bb1ad6e"}, + {file = "grpcio-1.68.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e8dbe3e00771bfe3d04feed8210fc6617006d06d9a2679b74605b9fed3e8362c"}, + {file = "grpcio-1.68.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:83bbf5807dc3ee94ce1de2dfe8a356e1d74101e4b9d7aa8c720cc4818a34aded"}, + {file = "grpcio-1.68.1-cp38-cp38-win32.whl", hash = "sha256:8cb620037a2fd9eeee97b4531880e439ebfcd6d7d78f2e7dcc3726428ab5ef63"}, + {file = "grpcio-1.68.1-cp38-cp38-win_amd64.whl", hash = "sha256:52fbf85aa71263380d330f4fce9f013c0798242e31ede05fcee7fbe40ccfc20d"}, + {file = "grpcio-1.68.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:cb400138e73969eb5e0535d1d06cae6a6f7a15f2cc74add320e2130b8179211a"}, + {file = "grpcio-1.68.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a1b988b40f2fd9de5c820f3a701a43339d8dcf2cb2f1ca137e2c02671cc83ac1"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:96f473cdacfdd506008a5d7579c9f6a7ff245a9ade92c3c0265eb76cc591914f"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37ea3be171f3cf3e7b7e412a98b77685eba9d4fd67421f4a34686a63a65d99f9"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ceb56c4285754e33bb3c2fa777d055e96e6932351a3082ce3559be47f8024f0"}, + {file = "grpcio-1.68.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dffd29a2961f3263a16d73945b57cd44a8fd0b235740cb14056f0612329b345e"}, + {file = "grpcio-1.68.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:025f790c056815b3bf53da850dd70ebb849fd755a4b1ac822cb65cd631e37d43"}, + {file = "grpcio-1.68.1-cp39-cp39-win32.whl", hash = "sha256:1098f03dedc3b9810810568060dea4ac0822b4062f537b0f53aa015269be0a76"}, + {file = "grpcio-1.68.1-cp39-cp39-win_amd64.whl", hash = "sha256:334ab917792904245a028f10e803fcd5b6f36a7b2173a820c0b5b076555825e1"}, + {file = "grpcio-1.68.1.tar.gz", hash = "sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.67.0)"] +protobuf = ["grpcio-tools (>=1.68.1)"] [[package]] name = "grpcio-health-checking" -version = "1.67.0" +version = "1.68.1" description = "Standard Health Checking Service for gRPC" optional = true python-versions = ">=3.8" files = [ - {file = "grpcio_health_checking-1.67.0-py3-none-any.whl", hash = "sha256:e9aa2e3ca8b05e7f3036530961a4f66b7e489ee4388b529186bad4512db8b00a"}, - {file = "grpcio_health_checking-1.67.0.tar.gz", hash = "sha256:3dea715d56e8250ff05ba49ef5117f836b240ff379be46360c26cefd9c9db11a"}, + {file = "grpcio_health_checking-1.68.1-py3-none-any.whl", hash = "sha256:2457627bf1223c7e57efebdbe50970d8e20ce536adfb8866535b21754b216bf4"}, + {file = "grpcio_health_checking-1.68.1.tar.gz", hash = "sha256:ea936cfa0c64a24afd8005873ea61b1acc83a941c00b56a6339c9b225c80a1a8"}, ] [package.dependencies] -grpcio = ">=1.67.0" +grpcio = ">=1.68.1" protobuf = ">=5.26.1,<6.0dev" [[package]] name = "grpcio-status" -version = "1.67.0" +version = "1.68.1" description = "Status proto mapping for gRPC" optional = true python-versions = ">=3.8" files = [ - {file = "grpcio_status-1.67.0-py3-none-any.whl", hash = "sha256:0e79e2e01ba41a6ca6ed9d7a825323c511fe1653a646f8014c7e3c8132527acc"}, - {file = "grpcio_status-1.67.0.tar.gz", hash = "sha256:c3e5a86fa007e9e263cd5f988a8a907484da4caab582874ea2a4a6092734046b"}, + {file = "grpcio_status-1.68.1-py3-none-any.whl", hash = "sha256:66f3d8847f665acfd56221333d66f7ad8927903d87242a482996bdb45e8d28fd"}, + {file = "grpcio_status-1.68.1.tar.gz", hash = "sha256:e1378d036c81a1610d7b4c7a146cd663dd13fcc915cf4d7d053929dba5bbb6e1"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.67.0" +grpcio = ">=1.68.1" protobuf = ">=5.26.1,<6.0dev" [[package]] name = "grpcio-tools" -version = "1.67.0" +version = "1.68.1" description = "Protobuf code generator for gRPC" optional = true python-versions = ">=3.8" files = [ - {file = "grpcio_tools-1.67.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:12aa38af76b5ef00a55808c7c374ed18d5dc7cc8081b717e56da3c50df1776e2"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b0b03d055127bbc7c629454804b53b5cad2cedfcf904576d159a8a04c22b8e66"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:02b0b50c59a8f7428326197027a2f586d216c46138c547f861533c46bff78bfe"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2afdfe151ed9edbd4a3fd646716f83b58010769c57f9c0aa1cf4c3bfb1240a8"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3eeb87575b2b360c5ef5aef22eb76cfdd6a255d2f628a48ab0e5a61a0039fb"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ead78089c4771605a1ff8894e47f2267440693f1beeee06fd5a788aede83370f"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0671dcdccef09ca4eb415c1d6f470a857c6486733c146676f6810a3ade1d42cb"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-win32.whl", hash = "sha256:a7398d90b8c7da479aec8f853d3664d5a93c209f8ac3bd41cb7ae4e8677a45c6"}, - {file = "grpcio_tools-1.67.0-cp310-cp310-win_amd64.whl", hash = "sha256:f7e7d70a74df7e07be7cceaa694b7e8e5f3bef8e0299906f60885ecf7a40adb4"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:655716bf931a22a090134d87953710033640996d31e36f5f9b0106ff5f552d8e"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:484ae782f9d3ff58e0bbb2f4cad14d5f5d9132fc701835b1dffd2c2a06f73ba6"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:f3e34de876efe1273f91e25ef241e449ed7f9411472dd9ff56d2039618017c30"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8301719edde2c3d388995703cdd962f558b76e9750405f772dce61402e4c3d0"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1629ea246044ccd473d9ac4c9f137a440d830b5e08d35225e1b354dbbb15b75d"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d77a3c5cec0065267ca1a0b2589ececd1277ce25aa67f13ec50c816ee6f26f7f"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf992bcc7d9e6eaa20705056e1b955593092a38cec1746fef389d873ab2056"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-win32.whl", hash = "sha256:7e6e3db119c38629e0767cdb2ee18726ecc87e2249117d4c9e7ce06ea8c894ea"}, - {file = "grpcio_tools-1.67.0-cp311-cp311-win_amd64.whl", hash = "sha256:c6c27aec301a0e6cf231f9ee1c467c64002af51170fa7c0f3bb10bbfcd03fee7"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:dca7f053cbdb26a587d4410ddb893877c585fb60a31f22fdd128e4f7c4dab27c"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:de8c4f68ffa690769d84329c17c7fdd5fbe4c61b8f8a0de03f1ad8ef8bb06963"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:6e4ecb24c27a78f09fead45d4ed873805d6026124ccb6793b6fb93a490b78ddf"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:004d6ef1b5f724480f05c0bdc904bf8c78c43d633c537d99abe51b52ce0cadeb"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dd257072c86eb9b36791b3674a513a215ba76bbdd38fc228f0e8c6dc5ce3524"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a8cca551317ed26e17d13b6ee27b2bd62f5fe9b3842b4e88389deb984f995848"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a7ac3b4f837c693142f6688b629d1f6408f6ab250d927159b572555f5339fe25"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-win32.whl", hash = "sha256:95feec33388e2a8f72c360a68efe6f0bfed9c771e94d21b7f2359d0010f60219"}, - {file = "grpcio_tools-1.67.0-cp312-cp312-win_amd64.whl", hash = "sha256:50a31d035193ebe7154181eac84734e25bdcdb36adba849d3b2adf1c3b0c382b"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:9ecb7c2e5da052a3feaeaa83d8f2a946a8feec8a50751b0e6175da982b49ebb1"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3c52164f2b9d41c6d75464bb45f45737dcb421e92e98d85d94fda100c67a24d8"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:471f58b919767290260d427dd9b760796e6208ee5fcda2f76bb8bd585ff842ec"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c6bcdf38f672721c093c92b1fb1f9a02a365acc5bd42e1c69fe6e904b26081"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:833b1eb9c03d28a798294523f75294055eff78fa897adf797876337b901afeb9"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:1db92ad6ade1946fc5705eb04956fcfdb3a0a4682de8dc3fce31cb97b6e4fcb8"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:38128310ded818e1044c0cd0979d76f7c0d3c3946a526a8aa39cd258624c3bf3"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-win32.whl", hash = "sha256:db57930dc20ab678311727883bdb9f122daf06c14f3fd3067c9ccedb7eb056c3"}, - {file = "grpcio_tools-1.67.0-cp313-cp313-win_amd64.whl", hash = "sha256:7de44d8d3bb920a4973a559f2950d03382fa4aed4880306416ffa73d24838477"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:793896648734aad3ad8f26795dcdd6040aecd35efef43fcbb67d221373e6379a"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:941418cba6a8adfcac3ff7ff3bdef00b55a44d673634c15bddcfa7778e49239e"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:0d63ff6be6f3d0294249fc7a21f26f06c9cc209130c5328907cd678406d7d232"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af80ced3ba49377ef7bec93e9ccbfa357875460e9a624ed12d9a7d5348741a76"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3c3fbb4a6d10764295540579492397bc7a3334e1a92dd17a4bc7b69159cf70a"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a05c10fb783f609d16e1f754ebad9bb432a1adbfc46139d154e8fd6b15f59988"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ea8af001f08c678ab59e2bf2614d8b09d62210e540f7af1129c172fe4fd330c7"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-win32.whl", hash = "sha256:004d329aee385fa874979196e5359a967c370d31813f61eba88043ccaa2e06d8"}, - {file = "grpcio_tools-1.67.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc43593bd051abb73a5d130fc041923144089ac459fb01165960106ebb686fd0"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:d285c036ddfc2618c4db60b584409dd8313d41473bd46177c763ea22ed9aeb1f"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:623fdad489447e1565d0ba5a818d54b4e74cd73800b6a32c4c009601c7f7a36c"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:24536af8a5f8e532fbd996c1763eff51526d1d1563f9499ff5ffffb9a08811f3"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd64a9a8eb675dd2aa59cb4b2ab025a3b02ae1bb9e483c7fb518ffa0f0755cda"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94378bc90fb008b0a56237748aa42c787fd86c392e7df3d65f0fe7fcd93844a"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d0f39a9d860a6768574cd77b5d9ad81513fa1c575d3a050d4e72e6d79dcd62f3"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c578f1306bfd0dd0668e24f8c04d61529928de2660217022a947a56be177bc2d"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-win32.whl", hash = "sha256:0c2cf8d09bdc05e0550ad413e0bc0d552500bb7f98d36079b7b9d38e064e02f7"}, - {file = "grpcio_tools-1.67.0-cp39-cp39-win_amd64.whl", hash = "sha256:cc570bcd9c9681bb011f746ea90cc50559be629227aaaaae9fde8549525f0287"}, - {file = "grpcio_tools-1.67.0.tar.gz", hash = "sha256:181b3d4e61b83142c182ec366f3079b0023509743986e54c9465ca38cac255f8"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:3a93ea324c5cbccdff55110777410d026dc1e69c3d47684ac97f57f7a77b9c70"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:94cbfb9482cfd7bdb5f081b94fa137a16e4fe031daa57a2cd85d8cb4e18dce25"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bbe7e1641859c858d0f4631f7f7c09e7302433f1aa037028d2419c1410945fac"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55c0f91c4294c5807796ed26af42509f3d68497942a92d9ee9f43b08768d6c3c"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85adc798fd3b57ab3e998b5897c5daab6840211ac16cdf3ba99901cb9b90094a"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0bdccb00709bf6180a80a353a99fa844cc0bb2d450cdf7fc6ab22c988bb6b4c"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2465e4d347b35dc0c007e074c79d5ded0a89c3aa26651e690f83593e0cc28af8"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-win32.whl", hash = "sha256:83c124a1776c1027da7d36584c8044cfed7a9f10e90f08dafde8d2a4cb822319"}, + {file = "grpcio_tools-1.68.1-cp310-cp310-win_amd64.whl", hash = "sha256:283fd1359d619d42c3346f1d8f0a70636a036a421178803a1ab8083fa4228a38"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:02f04de42834129eb54bb12469160ab631a0395d6a2b77975381c02b994086c3"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:92b6aab37095879ef9ee428dd171740ff794f4c7a66bc1cc7280cd0051f8cd96"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:1f0ac6ac5e1e33b998511981b3ef36489501833413354f3597b97a3452d7d7ba"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28e0bca3a262af86557f30e30ddf2fadc2324ee05cd7352716924cc7f83541f1"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12239cf5ca6b7b4937103953cf35c49683d935e32e98596fe52dd35168aa86e6"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8e48d8884fcf6b182c73d0560a183404458e30a0f479918b88ca8fbd48b8b05f"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4e8059469847441855322da16fa2c0f9787b996c237a98778210e31188a8652"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-win32.whl", hash = "sha256:21815d54a83effbd2600d16382a7897298cfeffe578557fc9a47b642cc8ddafe"}, + {file = "grpcio_tools-1.68.1-cp311-cp311-win_amd64.whl", hash = "sha256:2114528723d9f12d3e24af3d433ec6f140deea1dd64d3bb1b4ebced217f1867c"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:d67a9d1ad22ff0d22715dba1d5f8f23ebd47cea84ccd20c90bf4690d988adc5b"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7f1e704ff73eb01afac51b63b74868a35aaa5d6f791fc63bd41af44a51aa232"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:e9f69988bd77db014795511c498e89a0db24bd47877e65921364114f88de3bee"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8585ec7d11fcc2bb635b39605a4466ca9fa28dbae0c184fe58f456da72cb9031"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c81d0be6c46fcbcd2cd126804060a95531cdf6d779436b2fbc68c8b4a7db2dc1"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6efdb02e75baf289935b5dad665f0e0f7c3311d86aae0cd2c709e2a8a34bb620"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ea367639e771e5a05f7320eb4ae2b27e09d2ec3baeae9819d1c590cc7eaaa08"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-win32.whl", hash = "sha256:a5b1021c9942bba7eca1555061e2d308f506198088a3a539fcb3633499c6635f"}, + {file = "grpcio_tools-1.68.1-cp312-cp312-win_amd64.whl", hash = "sha256:315ad9c28940c95e85e57aeca309d298113175c2d5e8221501a05a51072f5477"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:67e49b5ede0cc8a0f988f41f7b72f6bc03180aecdb5213bd985bc1bbfd9ffdac"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b78e38f953062d45ff92ec940da292dc9bfbf26de492c8dc44e12b13493a8e80"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:8ebe9df5bab4121e8f51e013a379be2027179a0c8013e89d686a1e5800e9c205"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be553e3ea7447ed9e2e2d089f3b0a77000e86d2681b3c77498c98dddffc62d22"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4877f3eabb6185b5691f5218fedc86a84a833734847a294048862ec910a2854"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:b98173e536e8f2779eff84a03409cca6497dc1fad3d10a47c8d881b2cb36259b"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:5b64035dcd0df70acf3af972c3f103b0ce141d29732fd94eaa8b38cf7c8e62fe"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-win32.whl", hash = "sha256:573f3ed3276df20c308797ae834ac6c5595b1dd2953b243eedadbcd986a287d7"}, + {file = "grpcio_tools-1.68.1-cp313-cp313-win_amd64.whl", hash = "sha256:c4539c6231015c40db879fbc0feaaf03adb4275c1bd2b4dd26e2323f2a13655a"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:3e0fc6dbc64efc7bb0fe23ce46587e0cbeb512142d543834c2bc9100c8f255ff"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:79337ac1b19610b99f93aa52ae05e5fbf96adbe60d54ecf192af44cc69118d19"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:eb7cae5f0232aba9057f26a45ef6b0a5633d36627fe49442c0985b6f44b67822"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25fe1bcbb558a477c525bec9d67e1469d47dddc9430e6e5c0d11f67f08cfc810"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce901f42037d1ebc7724e721180d03e33163d5acf0a62c52728e6c36117c5e9"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3c213c2208c42dce2a5fc7cfb2b952a3c22ef019812f9f27bd54c6e00ee0720e"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff6ae5031a03ab90e9c508d12914438b73efd44b5eed9946bf8974c453d0ed57"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-win32.whl", hash = "sha256:41e631e72b6b94eb6f3d9cd533c682249f82fc58007c7561f6e521b884a6347e"}, + {file = "grpcio_tools-1.68.1-cp38-cp38-win_amd64.whl", hash = "sha256:69fb93761f116a5b063fb4f6150023c4d785304b37adcebf561b95018f9b40ae"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:31c703dba465956acb83adc105d61297459d0d14b512441d827f6c040cbffe2b"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1093f441751689d225916e3fe02daf98d2becab688b9e167bd2c38454ec50906"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:3543b9205e5b88d2280493aa9b55d35ce9cc45b7a0891c9d84c200652802e22a"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79d575cc5a522b9920d9a07387976fc02d162bdf97ba51cf91fabdca8dfdb491"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d546e4a506288d6227acc0eb625039c5e1ad96218c8cfe9ecf661a41e15e442e"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:aced9c7a4edbf6eff73720bfa6fefd9053ae294535a488dfb92a372913eda10d"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3c08d1a244b5025ba3f8ef81d0885b431b93cc20bc4560add4cdfcf38c1bfad"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-win32.whl", hash = "sha256:049f05a3f227e9f696059a20b2858e6d7c1cd6037d8471306d7ab7627b1a4ce4"}, + {file = "grpcio_tools-1.68.1-cp39-cp39-win_amd64.whl", hash = "sha256:4c3599c75b1157e6bda24cdbdadb023bf0fe1085aa1e0047a1f35a8778f9b56e"}, + {file = "grpcio_tools-1.68.1.tar.gz", hash = "sha256:2413a17ad16c9c821b36e4a67fc64c37b9e4636ab1c3a07778018801378739ba"}, ] [package.dependencies] -grpcio = ">=1.67.0" +grpcio = ">=1.68.1" protobuf = ">=5.26.1,<6.0dev" setuptools = "*" @@ -1577,13 +1570,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.6" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = true python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -1634,13 +1627,13 @@ files = [ [[package]] name = "huggingface-hub" -version = "0.26.1" +version = "0.26.5" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = true python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.26.1-py3-none-any.whl", hash = "sha256:5927a8fc64ae68859cd954b7cc29d1c8390a5e15caba6d3d349c973be8fdacf3"}, - {file = "huggingface_hub-0.26.1.tar.gz", hash = "sha256:414c0d9b769eecc86c70f9d939d0f48bb28e8461dd1130021542eff0212db890"}, + {file = "huggingface_hub-0.26.5-py3-none-any.whl", hash = "sha256:fb7386090bbe892072e64b85f7c4479fd2d65eea5f2543327c970d5169e83924"}, + {file = "huggingface_hub-0.26.5.tar.gz", hash = "sha256:1008bd18f60bfb65e8dbc0a97249beeeaa8c99d3c2fa649354df9fa5a13ed83b"}, ] [package.dependencies] @@ -1679,13 +1672,13 @@ files = [ [[package]] name = "identify" -version = "2.6.1" +version = "2.6.3" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, + {file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"}, + {file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"}, ] [package.extras] @@ -1769,84 +1762,87 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.6.1" +version = "0.8.2" description = "Fast iterable JSON parser." optional = true python-versions = ">=3.8" files = [ - {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, - {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e02f7a27f2bcc15b7d455c9df05df8ffffcc596a2a541eeda9a3110326e7a3"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed69a7971d67b08f152c17c638f0e8c2aa207e9dd3a5fcd3cba294d39b5a8d2d"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2019d966e98f7c6df24b3b8363998575f47d26471bfb14aade37630fae836a1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36c0b51a285b68311e207a76c385650322734c8717d16c2eb8af75c9d69506e7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:220e0963b4fb507c525c8f58cde3da6b1be0bfddb7ffd6798fb8f2531226cdb1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa25c7a9bf7875a141182b9c95aed487add635da01942ef7ca726e42a0c09058"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e90552109ca8ccd07f47ca99c8a1509ced93920d271bb81780a973279974c5ab"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:67723a011964971864e0b484b0ecfee6a14de1533cff7ffd71189e92103b38a8"}, - {file = "jiter-0.6.1-cp310-none-win32.whl", hash = "sha256:33af2b7d2bf310fdfec2da0177eab2fedab8679d1538d5b86a633ebfbbac4edd"}, - {file = "jiter-0.6.1-cp310-none-win_amd64.whl", hash = "sha256:7cea41c4c673353799906d940eee8f2d8fd1d9561d734aa921ae0f75cb9732f4"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b03c24e7da7e75b170c7b2b172d9c5e463aa4b5c95696a368d52c295b3f6847f"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:47fee1be677b25d0ef79d687e238dc6ac91a8e553e1a68d0839f38c69e0ee491"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f0d2f6e01a8a0fb0eab6d0e469058dab2be46ff3139ed2d1543475b5a1d8e7"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b809e39e342c346df454b29bfcc7bca3d957f5d7b60e33dae42b0e5ec13e027"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e9ac7c2f092f231f5620bef23ce2e530bd218fc046098747cc390b21b8738a7a"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e51a2d80d5fe0ffb10ed2c82b6004458be4a3f2b9c7d09ed85baa2fbf033f54b"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3343d4706a2b7140e8bd49b6c8b0a82abf9194b3f0f5925a78fc69359f8fc33c"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82521000d18c71e41c96960cb36e915a357bc83d63a8bed63154b89d95d05ad1"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c843e7c1633470708a3987e8ce617ee2979ee18542d6eb25ae92861af3f1d62"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a2e861658c3fe849efc39b06ebb98d042e4a4c51a8d7d1c3ddc3b1ea091d0784"}, - {file = "jiter-0.6.1-cp311-none-win32.whl", hash = "sha256:7d72fc86474862c9c6d1f87b921b70c362f2b7e8b2e3c798bb7d58e419a6bc0f"}, - {file = "jiter-0.6.1-cp311-none-win_amd64.whl", hash = "sha256:3e36a320634f33a07794bb15b8da995dccb94f944d298c8cfe2bd99b1b8a574a"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1fad93654d5a7dcce0809aff66e883c98e2618b86656aeb2129db2cd6f26f867"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4e6e340e8cd92edab7f6a3a904dbbc8137e7f4b347c49a27da9814015cc0420c"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:691352e5653af84ed71763c3c427cff05e4d658c508172e01e9c956dfe004aba"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:defee3949313c1f5b55e18be45089970cdb936eb2a0063f5020c4185db1b63c9"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26d2bdd5da097e624081c6b5d416d3ee73e5b13f1703bcdadbb1881f0caa1933"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18aa9d1626b61c0734b973ed7088f8a3d690d0b7f5384a5270cd04f4d9f26c86"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3567c8228afa5ddcce950631c6b17397ed178003dc9ee7e567c4c4dcae9fa0"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5c0507131c922defe3f04c527d6838932fcdfd69facebafd7d3574fa3395314"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:540fcb224d7dc1bcf82f90f2ffb652df96f2851c031adca3c8741cb91877143b"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e7b75436d4fa2032b2530ad989e4cb0ca74c655975e3ff49f91a1a3d7f4e1df2"}, - {file = "jiter-0.6.1-cp312-none-win32.whl", hash = "sha256:883d2ced7c21bf06874fdeecab15014c1c6d82216765ca6deef08e335fa719e0"}, - {file = "jiter-0.6.1-cp312-none-win_amd64.whl", hash = "sha256:91e63273563401aadc6c52cca64a7921c50b29372441adc104127b910e98a5b6"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:852508a54fe3228432e56019da8b69208ea622a3069458252f725d634e955b31"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f491cc69ff44e5a1e8bc6bf2b94c1f98d179e1aaf4a554493c171a5b2316b701"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc56c8f0b2a28ad4d8047f3ae62d25d0e9ae01b99940ec0283263a04724de1f3"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51b58f7a0d9e084a43b28b23da2b09fc5e8df6aa2b6a27de43f991293cab85fd"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f79ce15099154c90ef900d69c6b4c686b64dfe23b0114e0971f2fecd306ec6c"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03a025b52009f47e53ea619175d17e4ded7c035c6fbd44935cb3ada11e1fd592"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74a8d93718137c021d9295248a87c2f9fdc0dcafead12d2930bc459ad40f885"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40b03b75f903975f68199fc4ec73d546150919cb7e534f3b51e727c4d6ccca5a"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:825651a3f04cf92a661d22cad61fc913400e33aa89b3e3ad9a6aa9dc8a1f5a71"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:928bf25eb69ddb292ab8177fe69d3fbf76c7feab5fce1c09265a7dccf25d3991"}, - {file = "jiter-0.6.1-cp313-none-win32.whl", hash = "sha256:352cd24121e80d3d053fab1cc9806258cad27c53cad99b7a3cac57cf934b12e4"}, - {file = "jiter-0.6.1-cp313-none-win_amd64.whl", hash = "sha256:be7503dd6f4bf02c2a9bacb5cc9335bc59132e7eee9d3e931b13d76fd80d7fda"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:31d8e00e1fb4c277df8ab6f31a671f509ebc791a80e5c61fdc6bc8696aaa297c"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77c296d65003cd7ee5d7b0965f6acbe6cffaf9d1fa420ea751f60ef24e85fed5"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeeb0c0325ef96c12a48ea7e23e2e86fe4838e6e0a995f464cf4c79fa791ceeb"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a31c6fcbe7d6c25d6f1cc6bb1cba576251d32795d09c09961174fe461a1fb5bd"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59e2b37f3b9401fc9e619f4d4badcab2e8643a721838bcf695c2318a0475ae42"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bae5ae4853cb9644144e9d0755854ce5108d470d31541d83f70ca7ecdc2d1637"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9df588e9c830b72d8db1dd7d0175af6706b0904f682ea9b1ca8b46028e54d6e9"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15f8395e835cf561c85c1adee72d899abf2733d9df72e9798e6d667c9b5c1f30"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a99d4e0b5fc3b05ea732d67eb2092fe894e95a90e6e413f2ea91387e228a307"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a311df1fa6be0ccd64c12abcd85458383d96e542531bafbfc0a16ff6feda588f"}, - {file = "jiter-0.6.1-cp38-none-win32.whl", hash = "sha256:81116a6c272a11347b199f0e16b6bd63f4c9d9b52bc108991397dd80d3c78aba"}, - {file = "jiter-0.6.1-cp38-none-win_amd64.whl", hash = "sha256:13f9084e3e871a7c0b6e710db54444088b1dd9fbefa54d449b630d5e73bb95d0"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f1c53615fcfec3b11527c08d19cff6bc870da567ce4e57676c059a3102d3a082"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f791b6a4da23238c17a81f44f5b55d08a420c5692c1fda84e301a4b036744eb1"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c97e90fec2da1d5f68ef121444c2c4fa72eabf3240829ad95cf6bbeca42a301"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbc1a66b4e41511209e97a2866898733c0110b7245791ac604117b7fb3fedb7"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e85f9e12cd8418ab10e1fcf0e335ae5bb3da26c4d13a0fd9e6a17a674783b6"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08be33db6dcc374c9cc19d3633af5e47961a7b10d4c61710bd39e48d52a35824"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:677be9550004f5e010d673d3b2a2b815a8ea07a71484a57d3f85dde7f14cf132"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8bd065be46c2eecc328e419d6557bbc37844c88bb07b7a8d2d6c91c7c4dedc9"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bd95375ce3609ec079a97c5d165afdd25693302c071ca60c7ae1cf826eb32022"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db459ed22d0208940d87f614e1f0ea5a946d29a3cfef71f7e1aab59b6c6b2afb"}, - {file = "jiter-0.6.1-cp39-none-win32.whl", hash = "sha256:d71c962f0971347bd552940ab96aa42ceefcd51b88c4ced8a27398182efa8d80"}, - {file = "jiter-0.6.1-cp39-none-win_amd64.whl", hash = "sha256:d465db62d2d10b489b7e7a33027c4ae3a64374425d757e963f86df5b5f2e7fc5"}, - {file = "jiter-0.6.1.tar.gz", hash = "sha256:e19cd21221fc139fb032e4112986656cb2739e9fe6d84c13956ab30ccc7d4449"}, + {file = "jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b"}, + {file = "jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08"}, + {file = "jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49"}, + {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d"}, + {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff"}, + {file = "jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43"}, + {file = "jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105"}, + {file = "jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b"}, + {file = "jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586"}, + {file = "jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc"}, + {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88"}, + {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6"}, + {file = "jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44"}, + {file = "jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855"}, + {file = "jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f"}, + {file = "jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887"}, + {file = "jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d"}, + {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152"}, + {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29"}, + {file = "jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e"}, + {file = "jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c"}, + {file = "jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84"}, + {file = "jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef"}, + {file = "jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1"}, + {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9"}, + {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05"}, + {file = "jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a"}, + {file = "jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865"}, + {file = "jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca"}, + {file = "jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0"}, + {file = "jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566"}, + {file = "jiter-0.8.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9e1fa156ee9454642adb7e7234a383884452532bc9d53d5af2d18d98ada1d79c"}, + {file = "jiter-0.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cf5dfa9956d96ff2efb0f8e9c7d055904012c952539a774305aaaf3abdf3d6c"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e52bf98c7e727dd44f7c4acb980cb988448faeafed8433c867888268899b298b"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a2ecaa3c23e7a7cf86d00eda3390c232f4d533cd9ddea4b04f5d0644faf642c5"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08d4c92bf480e19fc3f2717c9ce2aa31dceaa9163839a311424b6862252c943e"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99d9a1eded738299ba8e106c6779ce5c3893cffa0e32e4485d680588adae6db8"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20be8b7f606df096e08b0b1b4a3c6f0515e8dac296881fe7461dfa0fb5ec817"}, + {file = "jiter-0.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d33f94615fcaf872f7fd8cd98ac3b429e435c77619777e8a449d9d27e01134d1"}, + {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:317b25e98a35ffec5c67efe56a4e9970852632c810d35b34ecdd70cc0e47b3b6"}, + {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc9043259ee430ecd71d178fccabd8c332a3bf1e81e50cae43cc2b28d19e4cb7"}, + {file = "jiter-0.8.2-cp38-cp38-win32.whl", hash = "sha256:fc5adda618205bd4678b146612ce44c3cbfdee9697951f2c0ffdef1f26d72b63"}, + {file = "jiter-0.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cd646c827b4f85ef4a78e4e58f4f5854fae0caf3db91b59f0d73731448a970c6"}, + {file = "jiter-0.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee"}, + {file = "jiter-0.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4"}, + {file = "jiter-0.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27"}, + {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841"}, + {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637"}, + {file = "jiter-0.8.2-cp39-cp39-win32.whl", hash = "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36"}, + {file = "jiter-0.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a"}, + {file = "jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d"}, ] [[package]] @@ -1860,6 +1856,17 @@ files = [ {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, ] +[[package]] +name = "json-repair" +version = "0.30.3" +description = "A package to repair broken json strings" +optional = false +python-versions = ">=3.9" +files = [ + {file = "json_repair-0.30.3-py3-none-any.whl", hash = "sha256:63bb588162b0958ae93d85356ecbe54c06b8c33f8a4834f93fa2719ea669804e"}, + {file = "json_repair-0.30.3.tar.gz", hash = "sha256:0ac56e7ae9253ee9c507a7e1a3a26799c9b0bbe5e2bec1b2cc5053e90d5b05e3"}, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -1898,13 +1905,13 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.12" +version = "0.3.23" description = "Building applications with LLMs through composability" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.12-py3-none-any.whl", hash = "sha256:46050d34f5fa36dc57dca971c6a26f505643dd05ee0492c7ac286d0a78a82037"}, - {file = "langchain_core-0.3.12.tar.gz", hash = "sha256:98a3c078e375786aa84939bfd1111263af2f3bc402bbe2cac9fa18a387459cf2"}, + {file = "langchain_core-0.3.23-py3-none-any.whl", hash = "sha256:550c0b996990830fa6515a71a1192a8a0343367999afc36d4ede14222941e420"}, + {file = "langchain_core-0.3.23.tar.gz", hash = "sha256:f9e175e3b82063cc3b160c2ca2b155832e1c6f915312e1204828f97d4aabf6e1"}, ] [package.dependencies] @@ -1921,66 +1928,66 @@ typing-extensions = ">=4.7" [[package]] name = "langchain-huggingface" -version = "0.1.0" +version = "0.1.2" description = "An integration package connecting Hugging Face and LangChain" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_huggingface-0.1.0-py3-none-any.whl", hash = "sha256:1b3dc44f460ba205f7c13cf48379a7f809ac9e056ea741bd12fc6414ac6aefb7"}, - {file = "langchain_huggingface-0.1.0.tar.gz", hash = "sha256:fa77a9545de77e7be4a7de134f692da413fc3b2b99d364fc9bcd0c6fa6fcb35c"}, + {file = "langchain_huggingface-0.1.2-py3-none-any.whl", hash = "sha256:7de5cfcae32bfb6a99c084fc16176f02583a4f8d94febb6bb45bed5b34699174"}, + {file = "langchain_huggingface-0.1.2.tar.gz", hash = "sha256:4a66d5c449298fd353bd84c9ed01f9bf4303bf2e4ffce14aab8c55c584eee57c"}, ] [package.dependencies] huggingface-hub = ">=0.23.0" -langchain-core = ">=0.3.0,<0.4" +langchain-core = ">=0.3.15,<0.4.0" sentence-transformers = ">=2.6.0" tokenizers = ">=0.19.1" transformers = ">=4.39.0" [[package]] name = "langchain-openai" -version = "0.2.3" +version = "0.2.12" description = "An integration package connecting OpenAI and LangChain" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_openai-0.2.3-py3-none-any.whl", hash = "sha256:f498c94817c980cb302439b95d3f3275cdf2743e022ee674692c75898523cf57"}, - {file = "langchain_openai-0.2.3.tar.gz", hash = "sha256:e142031704de1104735f503f76352c53b27ac0a2806466392993c4508c42bf0c"}, + {file = "langchain_openai-0.2.12-py3-none-any.whl", hash = "sha256:916965c45584d9ea565825ad3bb7629b1ff57f12f36d4b937e5b7d65903839d6"}, + {file = "langchain_openai-0.2.12.tar.gz", hash = "sha256:8b92096623065a2820e89aa5fb0a262fb109d56c346e3b09ba319af424c45cd1"}, ] [package.dependencies] -langchain-core = ">=0.3.12,<0.4.0" -openai = ">=1.52.0,<2.0.0" +langchain-core = ">=0.3.21,<0.4.0" +openai = ">=1.55.3,<2.0.0" tiktoken = ">=0.7,<1" [[package]] name = "langchain-text-splitters" -version = "0.3.0" +version = "0.3.2" description = "LangChain text splitting utilities" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_text_splitters-0.3.0-py3-none-any.whl", hash = "sha256:e84243e45eaff16e5b776cd9c81b6d07c55c010ebcb1965deb3d1792b7358e83"}, - {file = "langchain_text_splitters-0.3.0.tar.gz", hash = "sha256:f9fe0b4d244db1d6de211e7343d4abc4aa90295aa22e1f0c89e51f33c55cd7ce"}, + {file = "langchain_text_splitters-0.3.2-py3-none-any.whl", hash = "sha256:0db28c53f41d1bc024cdb3b1646741f6d46d5371e90f31e7e7c9fbe75d01c726"}, + {file = "langchain_text_splitters-0.3.2.tar.gz", hash = "sha256:81e6515d9901d6dd8e35fb31ccd4f30f76d44b771890c789dc835ef9f16204df"}, ] [package.dependencies] -langchain-core = ">=0.3.0,<0.4.0" +langchain-core = ">=0.3.15,<0.4.0" [[package]] name = "langsmith" -version = "0.1.137" +version = "0.1.147" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = true python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.137-py3-none-any.whl", hash = "sha256:4256d5c61133749890f7b5c88321dbb133ce0f440c621ea28e76513285859b81"}, - {file = "langsmith-0.1.137.tar.gz", hash = "sha256:56cdfcc6c74cb20a3f437d5bd144feb5bf93f54c5a2918d1e568cbd084a372d4"}, + {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, + {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, ] [package.dependencies] httpx = ">=0.23.0,<1" -orjson = ">=3.9.14,<4.0.0" +orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""} pydantic = [ {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, @@ -1988,15 +1995,18 @@ pydantic = [ requests = ">=2,<3" requests-toolbelt = ">=1.0.0,<2.0.0" +[package.extras] +langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"] + [[package]] name = "llama-cloud" -version = "0.1.4" +version = "0.1.6" description = "" optional = true python-versions = "<4,>=3.8" files = [ - {file = "llama_cloud-0.1.4-py3-none-any.whl", hash = "sha256:cfca6c4e0a87468b922d732f0f313a2ecd3a8e0bf74382ee80829ce49dcbc5e0"}, - {file = "llama_cloud-0.1.4.tar.gz", hash = "sha256:6f0155979bd96160951cb812c48836f1face037bc79ccfd8d185b18ef4c9faf8"}, + {file = "llama_cloud-0.1.6-py3-none-any.whl", hash = "sha256:43595081e03ff552fd18d9553fcaada897ff267456c0f89f4cb098b927dc4dc7"}, + {file = "llama_cloud-0.1.6.tar.gz", hash = "sha256:21200f6fdd46e08455d34b136f645ce6b8c3800e0ae13d8077913171a921da5a"}, ] [package.dependencies] @@ -2126,13 +2136,13 @@ llama-index-core = ">=0.10.48.post1,<0.11.0" [[package]] name = "llama-index-legacy" -version = "0.9.48.post3" +version = "0.9.48.post4" description = "Interface between LLMs and your data" optional = true python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index_legacy-0.9.48.post3-py3-none-any.whl", hash = "sha256:04221320d84d96ba9ee3e21e5055bd8527cbd769e8f1c60cf0368ed907e012a2"}, - {file = "llama_index_legacy-0.9.48.post3.tar.gz", hash = "sha256:f6969f1085efb0abebd6367e46f3512020f3f6b9c086f458a519830dd61e8206"}, + {file = "llama_index_legacy-0.9.48.post4-py3-none-any.whl", hash = "sha256:4b817d7c343fb5f7f00c4410eff519f320013b8d5f24c4fedcf270c471f92038"}, + {file = "llama_index_legacy-0.9.48.post4.tar.gz", hash = "sha256:f8a9764e7e134a52bfef5e53d2d62561bfc01fc09874c51cc001df6f5302ae30"}, ] [package.dependencies] @@ -2346,13 +2356,13 @@ files = [ [[package]] name = "marshmallow" -version = "3.23.0" +version = "3.23.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = true python-versions = ">=3.9" files = [ - {file = "marshmallow-3.23.0-py3-none-any.whl", hash = "sha256:82f20a2397834fe6d9611b241f2f7e7b680ed89c49f84728a1ad937be6b4bdf4"}, - {file = "marshmallow-3.23.0.tar.gz", hash = "sha256:98d8827a9f10c03d44ead298d2e99c6aea8197df18ccfad360dae7f89a50da2e"}, + {file = "marshmallow-3.23.1-py3-none-any.whl", hash = "sha256:fece2eb2c941180ea1b7fcbd4a83c51bfdd50093fdd3ad2585ee5e1df2508491"}, + {file = "marshmallow-3.23.1.tar.gz", hash = "sha256:3a8dfda6edd8dcdbf216c0ede1d1e78d230a6dc9c5a088f58c4083b974a0d468"}, ] [package.dependencies] @@ -2360,18 +2370,18 @@ packaging = ">=17.0" [package.extras] dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] -docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.14)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "simplejson"] [[package]] name = "mistralai" -version = "1.1.0" +version = "1.2.5" description = "Python Client SDK for the Mistral AI API." optional = true python-versions = "<4.0,>=3.8" files = [ - {file = "mistralai-1.1.0-py3-none-any.whl", hash = "sha256:eea0938975195f331d0ded12d14e3c982f09f1b68210200ed4ff0c6b9b22d0fb"}, - {file = "mistralai-1.1.0.tar.gz", hash = "sha256:9d1fe778e0e8c6ddab714e6a64c6096bd39cfe119ff38ceb5019d8e089df08ba"}, + {file = "mistralai-1.2.5-py3-none-any.whl", hash = "sha256:5f0ef2680ead0329569111face1bf2ff7c67c454d43aa0e21324a8faf6c3ab22"}, + {file = "mistralai-1.2.5.tar.gz", hash = "sha256:05d4130f79704e3b19c0b6320944a348547879fce6894feeb72d9e9d0ee65151"}, ] [package.dependencies] @@ -2379,7 +2389,7 @@ eval-type-backport = ">=0.2.0,<0.3.0" httpx = ">=0.27.0,<0.28.0" jsonpath-python = ">=1.0.6,<2.0.0" pydantic = ">=2.9.0,<3.0.0" -python-dateutil = "2.8.2" +python-dateutil = ">=2.8.2,<3.0.0" typing-inspect = ">=0.9.0,<0.10.0" [package.extras] @@ -2572,21 +2582,21 @@ files = [ [[package]] name = "neo4j" -version = "5.25.0" +version = "5.27.0" description = "Neo4j Bolt driver for Python" optional = false python-versions = ">=3.7" files = [ - {file = "neo4j-5.25.0-py3-none-any.whl", hash = "sha256:df310eee9a4f9749fb32bb9f1aa68711ac417b7eba3e42faefd6848038345ffa"}, - {file = "neo4j-5.25.0.tar.gz", hash = "sha256:7c82001c45319092cc0b5df4c92894553b7ab97bd4f59655156fa9acab83aec9"}, + {file = "neo4j-5.27.0-py3-none-any.whl", hash = "sha256:929c14b9e5341267324eca170b39d1798b032bffacc26a0529eacaf678ae483f"}, + {file = "neo4j-5.27.0.tar.gz", hash = "sha256:f82ee807cd15b178898d83f41a66372e11719a25dd487fd7bea48fd4b7323765"}, ] [package.dependencies] pytz = "*" [package.extras] -numpy = ["numpy (>=1.7.0,<2.0.0)"] -pandas = ["numpy (>=1.7.0,<2.0.0)", "pandas (>=1.1.0,<3.0.0)"] +numpy = ["numpy (>=1.7.0,<3.0.0)"] +pandas = ["numpy (>=1.7.0,<3.0.0)", "pandas (>=1.1.0,<3.0.0)"] pyarrow = ["pyarrow (>=1.0.0)"] [[package]] @@ -2856,13 +2866,13 @@ files = [ [[package]] name = "openai" -version = "1.52.2" +version = "1.57.1" description = "The official Python library for the openai API" optional = true -python-versions = ">=3.7.1" +python-versions = ">=3.8" files = [ - {file = "openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc"}, - {file = "openai-1.52.2.tar.gz", hash = "sha256:87b7d0f69d85f5641678d414b7ee3082363647a5c66a462ed7f3ccb59582da0d"}, + {file = "openai-1.57.1-py3-none-any.whl", hash = "sha256:3865686c927e93492d1145938d4a24b634951531c4b2769d43ca5dbd4b25d8fd"}, + {file = "openai-1.57.1.tar.gz", hash = "sha256:a95f22e04ab3df26e64a15d958342265e802314131275908b3b3e36f8c5d4377"}, ] [package.dependencies] @@ -2880,80 +2890,97 @@ datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] [[package]] name = "orjson" -version = "3.10.10" +version = "3.10.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = true python-versions = ">=3.8" files = [ - {file = "orjson-3.10.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b788a579b113acf1c57e0a68e558be71d5d09aa67f62ca1f68e01117e550a998"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:804b18e2b88022c8905bb79bd2cbe59c0cd014b9328f43da8d3b28441995cda4"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9972572a1d042ec9ee421b6da69f7cc823da5962237563fa548ab17f152f0b9b"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc6993ab1c2ae7dd0711161e303f1db69062955ac2668181bfdf2dd410e65258"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d78e4cacced5781b01d9bc0f0cd8b70b906a0e109825cb41c1b03f9c41e4ce86"}, - {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6eb2598df518281ba0cbc30d24c5b06124ccf7e19169e883c14e0831217a0bc"}, - {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23776265c5215ec532de6238a52707048401a568f0fa0d938008e92a147fe2c7"}, - {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cc2a654c08755cef90b468ff17c102e2def0edd62898b2486767204a7f5cc9c"}, - {file = "orjson-3.10.10-cp310-none-win32.whl", hash = "sha256:081b3fc6a86d72efeb67c13d0ea7c030017bd95f9868b1e329a376edc456153b"}, - {file = "orjson-3.10.10-cp310-none-win_amd64.whl", hash = "sha256:ff38c5fb749347768a603be1fb8a31856458af839f31f064c5aa74aca5be9efe"}, - {file = "orjson-3.10.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:879e99486c0fbb256266c7c6a67ff84f46035e4f8749ac6317cc83dacd7f993a"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019481fa9ea5ff13b5d5d95e6fd5ab25ded0810c80b150c2c7b1cc8660b662a7"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0dd57eff09894938b4c86d4b871a479260f9e156fa7f12f8cad4b39ea8028bb5"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbde6d70cd95ab4d11ea8ac5e738e30764e510fc54d777336eec09bb93b8576c"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2625cb37b8fb42e2147404e5ff7ef08712099197a9cd38895006d7053e69d6"}, - {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbf3c20c6a7db69df58672a0d5815647ecf78c8e62a4d9bd284e8621c1fe5ccb"}, - {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:75c38f5647e02d423807d252ce4528bf6a95bd776af999cb1fb48867ed01d1f6"}, - {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23458d31fa50ec18e0ec4b0b4343730928296b11111df5f547c75913714116b2"}, - {file = "orjson-3.10.10-cp311-none-win32.whl", hash = "sha256:2787cd9dedc591c989f3facd7e3e86508eafdc9536a26ec277699c0aa63c685b"}, - {file = "orjson-3.10.10-cp311-none-win_amd64.whl", hash = "sha256:6514449d2c202a75183f807bc755167713297c69f1db57a89a1ef4a0170ee269"}, - {file = "orjson-3.10.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8564f48f3620861f5ef1e080ce7cd122ee89d7d6dacf25fcae675ff63b4d6e05"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bf161a32b479034098c5b81f2608f09167ad2fa1c06abd4e527ea6bf4837a9"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b65c93617bcafa7f04b74ae8bc2cc214bd5cb45168a953256ff83015c6747d"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8e28406f97fc2ea0c6150f4c1b6e8261453318930b334abc419214c82314f85"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4d0d9fe174cc7a5bdce2e6c378bcdb4c49b2bf522a8f996aa586020e1b96cee"}, - {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3be81c42f1242cbed03cbb3973501fcaa2675a0af638f8be494eaf37143d999"}, - {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65f9886d3bae65be026219c0a5f32dbbe91a9e6272f56d092ab22561ad0ea33b"}, - {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b"}, - {file = "orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f"}, - {file = "orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f"}, - {file = "orjson-3.10.10-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44bffae68c291f94ff5a9b4149fe9d1bdd4cd0ff0fb575bcea8351d48db629a1"}, - {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e27b4c6437315df3024f0835887127dac2a0a3ff643500ec27088d2588fa5ae1"}, - {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca84df16d6b49325a4084fd8b2fe2229cb415e15c46c529f868c3387bb1339d"}, - {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c14ce70e8f39bd71f9f80423801b5d10bf93d1dceffdecd04df0f64d2c69bc01"}, - {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:24ac62336da9bda1bd93c0491eff0613003b48d3cb5d01470842e7b52a40d5b4"}, - {file = "orjson-3.10.10-cp313-none-win32.whl", hash = "sha256:eb0a42831372ec2b05acc9ee45af77bcaccbd91257345f93780a8e654efc75db"}, - {file = "orjson-3.10.10-cp313-none-win_amd64.whl", hash = "sha256:f0c4f37f8bf3f1075c6cc8dd8a9f843689a4b618628f8812d0a71e6968b95ffd"}, - {file = "orjson-3.10.10-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:829700cc18503efc0cf502d630f612884258020d98a317679cd2054af0259568"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0ceb5e0e8c4f010ac787d29ae6299846935044686509e2f0f06ed441c1ca949"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c25908eb86968613216f3db4d3003f1c45d78eb9046b71056ca327ff92bdbd4"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:218cb0bc03340144b6328a9ff78f0932e642199ac184dd74b01ad691f42f93ff"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2277ec2cea3775640dc81ab5195bb5b2ada2fe0ea6eee4677474edc75ea6785"}, - {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:848ea3b55ab5ccc9d7bbd420d69432628b691fba3ca8ae3148c35156cbd282aa"}, - {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e3e67b537ac0c835b25b5f7d40d83816abd2d3f4c0b0866ee981a045287a54f3"}, - {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7948cfb909353fce2135dcdbe4521a5e7e1159484e0bb024c1722f272488f2b8"}, - {file = "orjson-3.10.10-cp38-none-win32.whl", hash = "sha256:78bee66a988f1a333dc0b6257503d63553b1957889c17b2c4ed72385cd1b96ae"}, - {file = "orjson-3.10.10-cp38-none-win_amd64.whl", hash = "sha256:f1d647ca8d62afeb774340a343c7fc023efacfd3a39f70c798991063f0c681dd"}, - {file = "orjson-3.10.10-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5a059afddbaa6dd733b5a2d76a90dbc8af790b993b1b5cb97a1176ca713b5df8"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f9b5c59f7e2a1a410f971c5ebc68f1995822837cd10905ee255f96074537ee6"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5ef198bafdef4aa9d49a4165ba53ffdc0a9e1c7b6f76178572ab33118afea25"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf29ce0bb5d3320824ec3d1508652421000ba466abd63bdd52c64bcce9eb1fa"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dddd5516bcc93e723d029c1633ae79c4417477b4f57dad9bfeeb6bc0315e654a"}, - {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12f2003695b10817f0fa8b8fca982ed7f5761dcb0d93cff4f2f9f6709903fd7"}, - {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:672f9874a8a8fb9bb1b771331d31ba27f57702c8106cdbadad8bda5d10bc1019"}, - {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dcbb0ca5fafb2b378b2c74419480ab2486326974826bbf6588f4dc62137570a"}, - {file = "orjson-3.10.10-cp39-none-win32.whl", hash = "sha256:d9bbd3a4b92256875cb058c3381b782649b9a3c68a4aa9a2fff020c2f9cfc1be"}, - {file = "orjson-3.10.10-cp39-none-win_amd64.whl", hash = "sha256:766f21487a53aee8524b97ca9582d5c6541b03ab6210fbaf10142ae2f3ced2aa"}, - {file = "orjson-3.10.10.tar.gz", hash = "sha256:37949383c4df7b4337ce82ee35b6d7471e55195efa7dcb45ab8226ceadb0fe3b"}, + {file = "orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2"}, + {file = "orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3"}, + {file = "orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509"}, + {file = "orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd"}, + {file = "orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79"}, + {file = "orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8"}, + {file = "orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c"}, + {file = "orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708"}, + {file = "orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb"}, + {file = "orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e"}, + {file = "orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc"}, + {file = "orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825"}, + {file = "orjson-3.10.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7d69af5b54617a5fac5c8e5ed0859eb798e2ce8913262eb522590239db6c6763"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ed119ea7d2953365724a7059231a44830eb6bbb0cfead33fcbc562f5fd8f935"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5fc1238ef197e7cad5c91415f524aaa51e004be5a9b35a1b8a84ade196f73f"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43509843990439b05f848539d6f6198d4ac86ff01dd024b2f9a795c0daeeab60"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f72e27a62041cfb37a3de512247ece9f240a561e6c8662276beaf4d53d406db4"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a904f9572092bb6742ab7c16c623f0cdccbad9eeb2d14d4aa06284867bddd31"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:855c0833999ed5dc62f64552db26f9be767434917d8348d77bacaab84f787d7b"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:897830244e2320f6184699f598df7fb9db9f5087d6f3f03666ae89d607e4f8ed"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:0b32652eaa4a7539f6f04abc6243619c56f8530c53bf9b023e1269df5f7816dd"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:36b4aa31e0f6a1aeeb6f8377769ca5d125db000f05c20e54163aef1d3fe8e833"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5535163054d6cbf2796f93e4f0dbc800f61914c0e3c4ed8499cf6ece22b4a3da"}, + {file = "orjson-3.10.12-cp38-none-win32.whl", hash = "sha256:90a5551f6f5a5fa07010bf3d0b4ca2de21adafbbc0af6cb700b63cd767266cb9"}, + {file = "orjson-3.10.12-cp38-none-win_amd64.whl", hash = "sha256:703a2fb35a06cdd45adf5d733cf613cbc0cb3ae57643472b16bc22d325b5fb6c"}, + {file = "orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69"}, + {file = "orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b"}, + {file = "orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548"}, + {file = "orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff"}, ] [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -3253,109 +3280,93 @@ virtualenv = ">=20.10.0" [[package]] name = "propcache" -version = "0.2.0" +version = "0.2.1" description = "Accelerated property cache" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, - {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, - {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, - {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, - {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, - {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, - {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, - {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, - {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, - {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, - {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, - {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, - {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, - {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, - {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, ] [[package]] @@ -3377,22 +3388,22 @@ testing = ["google-api-core (>=1.31.5)"] [[package]] name = "protobuf" -version = "5.28.3" +version = "5.29.1" description = "" optional = true python-versions = ">=3.8" files = [ - {file = "protobuf-5.28.3-cp310-abi3-win32.whl", hash = "sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24"}, - {file = "protobuf-5.28.3-cp310-abi3-win_amd64.whl", hash = "sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868"}, - {file = "protobuf-5.28.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687"}, - {file = "protobuf-5.28.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584"}, - {file = "protobuf-5.28.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135"}, - {file = "protobuf-5.28.3-cp38-cp38-win32.whl", hash = "sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548"}, - {file = "protobuf-5.28.3-cp38-cp38-win_amd64.whl", hash = "sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b"}, - {file = "protobuf-5.28.3-cp39-cp39-win32.whl", hash = "sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535"}, - {file = "protobuf-5.28.3-cp39-cp39-win_amd64.whl", hash = "sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36"}, - {file = "protobuf-5.28.3-py3-none-any.whl", hash = "sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed"}, - {file = "protobuf-5.28.3.tar.gz", hash = "sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b"}, + {file = "protobuf-5.29.1-cp310-abi3-win32.whl", hash = "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110"}, + {file = "protobuf-5.29.1-cp310-abi3-win_amd64.whl", hash = "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34"}, + {file = "protobuf-5.29.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18"}, + {file = "protobuf-5.29.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155"}, + {file = "protobuf-5.29.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d"}, + {file = "protobuf-5.29.1-cp38-cp38-win32.whl", hash = "sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853"}, + {file = "protobuf-5.29.1-cp38-cp38-win_amd64.whl", hash = "sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331"}, + {file = "protobuf-5.29.1-cp39-cp39-win32.whl", hash = "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57"}, + {file = "protobuf-5.29.1-cp39-cp39-win_amd64.whl", hash = "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c"}, + {file = "protobuf-5.29.1-py3-none-any.whl", hash = "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0"}, + {file = "protobuf-5.29.1.tar.gz", hash = "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb"}, ] [[package]] @@ -3433,22 +3444,19 @@ files = [ [[package]] name = "pydantic" -version = "2.9.2" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.4" -typing-extensions = [ - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, -] +pydantic-core = "2.27.1" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -3456,100 +3464,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.4" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, - {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, - {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, - {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, - {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, - {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, - {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, - {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, - {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, - {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, - {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, - {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, - {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, - {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -3612,13 +3631,13 @@ image = ["Pillow (>=8.0.0)"] [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -3652,13 +3671,13 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -3766,13 +3785,13 @@ files = [ [[package]] name = "qdrant-client" -version = "1.12.0" +version = "1.12.1" description = "Client library for the Qdrant vector search engine" optional = true python-versions = ">=3.8" files = [ - {file = "qdrant_client-1.12.0-py3-none-any.whl", hash = "sha256:6db5ac1e244272f8b67e9dbc0da557816efef6f919cd8ee134469c751fe72c03"}, - {file = "qdrant_client-1.12.0.tar.gz", hash = "sha256:f443db39988aa6ff7c7a605770084ddaca8fdb5f8b22f77c10e661bdf0974cda"}, + {file = "qdrant_client-1.12.1-py3-none-any.whl", hash = "sha256:b2d17ce18e9e767471368380dd3bbc4a0e3a0e2061fedc9af3542084b48451e0"}, + {file = "qdrant_client-1.12.1.tar.gz", hash = "sha256:35e8e646f75b7b883b3d2d0ee4c69c5301000bba41c82aa546e985db0f1aeb72"}, ] [package.dependencies] @@ -3793,105 +3812,105 @@ fastembed-gpu = ["fastembed-gpu (==0.3.6)"] [[package]] name = "regex" -version = "2024.9.11" +version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = true python-versions = ">=3.8" files = [ - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, - {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, - {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, - {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, - {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, - {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, - {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, - {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, - {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, - {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, - {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, - {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, - {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, - {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, ] [[package]] @@ -4103,37 +4122,41 @@ torch = ["safetensors[numpy]", "torch (>=1.10)"] [[package]] name = "scikit-learn" -version = "1.5.2" +version = "1.6.0" description = "A set of python modules for machine learning and data mining" optional = true python-versions = ">=3.9" files = [ - {file = "scikit_learn-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:299406827fb9a4f862626d0fe6c122f5f87f8910b86fe5daa4c32dcd742139b6"}, - {file = "scikit_learn-1.5.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2d4cad1119c77930b235579ad0dc25e65c917e756fe80cab96aa3b9428bd3fb0"}, - {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c412ccc2ad9bf3755915e3908e677b367ebc8d010acbb3f182814524f2e5540"}, - {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a686885a4b3818d9e62904d91b57fa757fc2bed3e465c8b177be652f4dd37c8"}, - {file = "scikit_learn-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:c15b1ca23d7c5f33cc2cb0a0d6aaacf893792271cddff0edbd6a40e8319bc113"}, - {file = "scikit_learn-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03b6158efa3faaf1feea3faa884c840ebd61b6484167c711548fce208ea09445"}, - {file = "scikit_learn-1.5.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1ff45e26928d3b4eb767a8f14a9a6efbf1cbff7c05d1fb0f95f211a89fd4f5de"}, - {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f763897fe92d0e903aa4847b0aec0e68cadfff77e8a0687cabd946c89d17e675"}, - {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8b0ccd4a902836493e026c03256e8b206656f91fbcc4fde28c57a5b752561f1"}, - {file = "scikit_learn-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6c16d84a0d45e4894832b3c4d0bf73050939e21b99b01b6fd59cbb0cf39163b6"}, - {file = "scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f932a02c3f4956dfb981391ab24bda1dbd90fe3d628e4b42caef3e041c67707a"}, - {file = "scikit_learn-1.5.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3b923d119d65b7bd555c73be5423bf06c0105678ce7e1f558cb4b40b0a5502b1"}, - {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd"}, - {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6"}, - {file = "scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1"}, - {file = "scikit_learn-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9a702e2de732bbb20d3bad29ebd77fc05a6b427dc49964300340e4c9328b3f5"}, - {file = "scikit_learn-1.5.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b0768ad641981f5d3a198430a1d31c3e044ed2e8a6f22166b4d546a5116d7908"}, - {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:178ddd0a5cb0044464fc1bfc4cca5b1833bfc7bb022d70b05db8530da4bb3dd3"}, - {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7284ade780084d94505632241bf78c44ab3b6f1e8ccab3d2af58e0e950f9c12"}, - {file = "scikit_learn-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:b7b0f9a0b1040830d38c39b91b3a44e1b643f4b36e36567b80b7c6bd2202a27f"}, - {file = "scikit_learn-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:757c7d514ddb00ae249832fe87100d9c73c6ea91423802872d9e74970a0e40b9"}, - {file = "scikit_learn-1.5.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:52788f48b5d8bca5c0736c175fa6bdaab2ef00a8f536cda698db61bd89c551c1"}, - {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:643964678f4b5fbdc95cbf8aec638acc7aa70f5f79ee2cdad1eec3df4ba6ead8"}, - {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca64b3089a6d9b9363cd3546f8978229dcbb737aceb2c12144ee3f70f95684b7"}, - {file = "scikit_learn-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:3bed4909ba187aca80580fe2ef370d9180dcf18e621a27c4cf2ef10d279a7efe"}, - {file = "scikit_learn-1.5.2.tar.gz", hash = "sha256:b4237ed7b3fdd0a4882792e68ef2545d5baa50aca3bb45aa7df468138ad8f94d"}, + {file = "scikit_learn-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:366fb3fa47dce90afed3d6106183f4978d6f24cfd595c2373424171b915ee718"}, + {file = "scikit_learn-1.6.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:59cd96a8d9f8dfd546f5d6e9787e1b989e981388d7803abbc9efdcde61e47460"}, + {file = "scikit_learn-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efa7a579606c73a0b3d210e33ea410ea9e1af7933fe324cb7e6fbafae4ea5948"}, + {file = "scikit_learn-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a46d3ca0f11a540b8eaddaf5e38172d8cd65a86cb3e3632161ec96c0cffb774c"}, + {file = "scikit_learn-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:5be4577769c5dde6e1b53de8e6520f9b664ab5861dd57acee47ad119fd7405d6"}, + {file = "scikit_learn-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f50b4f24cf12a81c3c09958ae3b864d7534934ca66ded3822de4996d25d7285"}, + {file = "scikit_learn-1.6.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eb9ae21f387826da14b0b9cb1034f5048ddb9182da429c689f5f4a87dc96930b"}, + {file = "scikit_learn-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0baa91eeb8c32632628874a5c91885eaedd23b71504d24227925080da075837a"}, + {file = "scikit_learn-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c716d13ba0a2f8762d96ff78d3e0cde90bc9c9b5c13d6ab6bb9b2d6ca6705fd"}, + {file = "scikit_learn-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:9aafd94bafc841b626681e626be27bf1233d5a0f20f0a6fdb4bee1a1963c6643"}, + {file = "scikit_learn-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:04a5ba45c12a5ff81518aa4f1604e826a45d20e53da47b15871526cda4ff5174"}, + {file = "scikit_learn-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:21fadfc2ad7a1ce8bd1d90f23d17875b84ec765eecbbfc924ff11fb73db582ce"}, + {file = "scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f34bb5fde90e020653bb84dcb38b6c83f90c70680dbd8c38bd9becbad7a127"}, + {file = "scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dad624cffe3062276a0881d4e441bc9e3b19d02d17757cd6ae79a9d192a0027"}, + {file = "scikit_learn-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fce7950a3fad85e0a61dc403df0f9345b53432ac0e47c50da210d22c60b6d85"}, + {file = "scikit_learn-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e5453b2e87ef8accedc5a8a4e6709f887ca01896cd7cc8a174fe39bd4bb00aef"}, + {file = "scikit_learn-1.6.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5fe11794236fb83bead2af26a87ced5d26e3370b8487430818b915dafab1724e"}, + {file = "scikit_learn-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61fe3dcec0d82ae280877a818ab652f4988371e32dd5451e75251bece79668b1"}, + {file = "scikit_learn-1.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44e3a51e181933bdf9a4953cc69c6025b40d2b49e238233f149b98849beb4bf"}, + {file = "scikit_learn-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:a17860a562bac54384454d40b3f6155200c1c737c9399e6a97962c63fce503ac"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:98717d3c152f6842d36a70f21e1468fb2f1a2f8f2624d9a3f382211798516426"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:34e20bfac8ff0ebe0ff20fb16a4d6df5dc4cc9ce383e00c2ab67a526a3c67b18"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba06d75815406091419e06dd650b91ebd1c5f836392a0d833ff36447c2b1bfa"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b6916d1cec1ff163c7d281e699d7a6a709da2f2c5ec7b10547e08cc788ddd3ae"}, + {file = "scikit_learn-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:66b1cf721a9f07f518eb545098226796c399c64abdcbf91c2b95d625068363da"}, + {file = "scikit_learn-1.6.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b35b60cf4cd6564b636e4a40516b3c61a4fa7a8b1f7a3ce80c38ebe04750bc3"}, + {file = "scikit_learn-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a73b1c2038c93bc7f4bf21f6c9828d5116c5d2268f7a20cfbbd41d3074d52083"}, + {file = "scikit_learn-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c3fa7d3dd5a0ec2d0baba0d644916fa2ab180ee37850c5d536245df916946bd"}, + {file = "scikit_learn-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:df778486a32518cda33818b7e3ce48c78cef1d5f640a6bc9d97c6d2e71449a51"}, + {file = "scikit_learn-1.6.0.tar.gz", hash = "sha256:9d58481f9f7499dff4196927aedd4285a0baec8caa3790efbe205f13de37dd6e"}, ] [package.dependencies] @@ -4145,11 +4168,11 @@ threadpoolctl = ">=3.1.0" [package.extras] benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] maintenance = ["conda-lock (==2.5.6)"] -tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] +tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.5.1)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" @@ -4195,13 +4218,13 @@ test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "po [[package]] name = "sentence-transformers" -version = "3.2.1" +version = "3.3.1" description = "State-of-the-Art Text Embeddings" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sentence_transformers-3.2.1-py3-none-any.whl", hash = "sha256:c507e069eea33d15f1f2c72f74d7ea93abef298152cc235ab5af5e3a7584f738"}, - {file = "sentence_transformers-3.2.1.tar.gz", hash = "sha256:9fc38e620e5e1beba31d538a451778c9ccdbad77119d90f59f5bce49c4148e79"}, + {file = "sentence_transformers-3.3.1-py3-none-any.whl", hash = "sha256:abffcc79dab37b7d18d21a26d5914223dd42239cfe18cb5e111c66c54b658ae7"}, + {file = "sentence_transformers-3.3.1.tar.gz", hash = "sha256:9635dbfb11c6b01d036b9cfcee29f7716ab64cf2407ad9f403a2e607da2ac48b"}, ] [package.dependencies] @@ -4214,7 +4237,7 @@ tqdm = "*" transformers = ">=4.41.0,<5.0.0" [package.extras] -dev = ["accelerate (>=0.20.3)", "datasets", "pre-commit", "pytest", "pytest-cov"] +dev = ["accelerate (>=0.20.3)", "datasets", "peft", "pre-commit", "pytest", "pytest-cov"] onnx = ["optimum[onnxruntime] (>=1.23.1)"] onnx-gpu = ["optimum[onnxruntime-gpu] (>=1.23.1)"] openvino = ["optimum-intel[openvino] (>=1.20.0)"] @@ -4222,23 +4245,23 @@ train = ["accelerate (>=0.20.3)", "datasets"] [[package]] name = "setuptools" -version = "75.2.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "shapely" @@ -4300,13 +4323,13 @@ test = ["pytest", "pytest-cov"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -4670,111 +4693,26 @@ blobfile = ["blobfile (>=2)"] [[package]] name = "tokenizers" -version = "0.20.1" +version = "0.21.0" description = "" optional = true python-versions = ">=3.7" files = [ - {file = "tokenizers-0.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:439261da7c0a5c88bda97acb284d49fbdaf67e9d3b623c0bfd107512d22787a9"}, - {file = "tokenizers-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03dae629d99068b1ea5416d50de0fea13008f04129cc79af77a2a6392792d93c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b61f561f329ffe4b28367798b89d60c4abf3f815d37413b6352bc6412a359867"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec870fce1ee5248a10be69f7a8408a234d6f2109f8ea827b4f7ecdbf08c9fd15"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d388d1ea8b7447da784e32e3b86a75cce55887e3b22b31c19d0b186b1c677800"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:299c85c1d21135bc01542237979bf25c32efa0d66595dd0069ae259b97fb2dbe"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96f6c14c9752bb82145636b614d5a78e9cde95edfbe0a85dad0dd5ddd6ec95c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc9e95ad49c932b80abfbfeaf63b155761e695ad9f8a58c52a47d962d76e310f"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f22dee205329a636148c325921c73cf3e412e87d31f4d9c3153b302a0200057b"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2ffd9a8895575ac636d44500c66dffaef133823b6b25067604fa73bbc5ec09d"}, - {file = "tokenizers-0.20.1-cp310-none-win32.whl", hash = "sha256:2847843c53f445e0f19ea842a4e48b89dd0db4e62ba6e1e47a2749d6ec11f50d"}, - {file = "tokenizers-0.20.1-cp310-none-win_amd64.whl", hash = "sha256:f9aa93eacd865f2798b9e62f7ce4533cfff4f5fbd50c02926a78e81c74e432cd"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4a717dcb08f2dabbf27ae4b6b20cbbb2ad7ed78ce05a829fae100ff4b3c7ff15"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f84dad1ff1863c648d80628b1b55353d16303431283e4efbb6ab1af56a75832"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:929c8f3afa16a5130a81ab5079c589226273ec618949cce79b46d96e59a84f61"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d10766473954397e2d370f215ebed1cc46dcf6fd3906a2a116aa1d6219bfedc3"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9300fac73ddc7e4b0330acbdda4efaabf74929a4a61e119a32a181f534a11b47"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ecaf7b0e39caeb1aa6dd6e0975c405716c82c1312b55ac4f716ef563a906969"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5170be9ec942f3d1d317817ced8d749b3e1202670865e4fd465e35d8c259de83"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f1ae08fa9aea5891cbd69df29913e11d3841798e0bfb1ff78b78e4e7ea0a4"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee86d4095d3542d73579e953c2e5e07d9321af2ffea6ecc097d16d538a2dea16"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:86dcd08da163912e17b27bbaba5efdc71b4fbffb841530fdb74c5707f3c49216"}, - {file = "tokenizers-0.20.1-cp311-none-win32.whl", hash = "sha256:9af2dc4ee97d037bc6b05fa4429ddc87532c706316c5e11ce2f0596dfcfa77af"}, - {file = "tokenizers-0.20.1-cp311-none-win_amd64.whl", hash = "sha256:899152a78b095559c287b4c6d0099469573bb2055347bb8154db106651296f39"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:407ab666b38e02228fa785e81f7cf79ef929f104bcccf68a64525a54a93ceac9"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f13a2d16032ebc8bd812eb8099b035ac65887d8f0c207261472803b9633cf3e"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98eee4dca22849fbb56a80acaa899eec5b72055d79637dd6aa15d5e4b8628c9"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47c1bcdd61e61136087459cb9e0b069ff23b5568b008265e5cbc927eae3387ce"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128c1110e950534426e2274837fc06b118ab5f2fa61c3436e60e0aada0ccfd67"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2e2d47a819d2954f2c1cd0ad51bb58ffac6f53a872d5d82d65d79bf76b9896d"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdd67a0e3503a9a7cf8bc5a4a49cdde5fa5bada09a51e4c7e1c73900297539bd"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b93d2e26d04da337ac407acec8b5d081d8d135e3e5066a88edd5bdb5aff89"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0c6a796ddcd9a19ad13cf146997cd5895a421fe6aec8fd970d69f9117bddb45c"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3ea919687aa7001a8ff1ba36ac64f165c4e89035f57998fa6cedcfd877be619d"}, - {file = "tokenizers-0.20.1-cp312-none-win32.whl", hash = "sha256:6d3ac5c1f48358ffe20086bf065e843c0d0a9fce0d7f0f45d5f2f9fba3609ca5"}, - {file = "tokenizers-0.20.1-cp312-none-win_amd64.whl", hash = "sha256:b0874481aea54a178f2bccc45aa2d0c99cd3f79143a0948af6a9a21dcc49173b"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:96af92e833bd44760fb17f23f402e07a66339c1dcbe17d79a9b55bb0cc4f038e"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:65f34e5b731a262dfa562820818533c38ce32a45864437f3d9c82f26c139ca7f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17f98fccb5c12ab1ce1f471731a9cd86df5d4bd2cf2880c5a66b229802d96145"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8c0fc3542cf9370bf92c932eb71bdeb33d2d4aeeb4126d9fd567b60bd04cb30"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b39356df4575d37f9b187bb623aab5abb7b62c8cb702867a1768002f814800c"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfdad27b0e50544f6b838895a373db6114b85112ba5c0cefadffa78d6daae563"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:094663dd0e85ee2e573126918747bdb40044a848fde388efb5b09d57bc74c680"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e4cf033a2aa207d7ac790e91adca598b679999710a632c4a494aab0fc3a1b2"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9310951c92c9fb91660de0c19a923c432f110dbfad1a2d429fbc44fa956bf64f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:05e41e302c315bd2ed86c02e917bf03a6cf7d2f652c9cee1a0eb0d0f1ca0d32c"}, - {file = "tokenizers-0.20.1-cp37-none-win32.whl", hash = "sha256:212231ab7dfcdc879baf4892ca87c726259fa7c887e1688e3f3cead384d8c305"}, - {file = "tokenizers-0.20.1-cp37-none-win_amd64.whl", hash = "sha256:896195eb9dfdc85c8c052e29947169c1fcbe75a254c4b5792cdbd451587bce85"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:741fb22788482d09d68e73ece1495cfc6d9b29a06c37b3df90564a9cfa688e6d"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10be14ebd8082086a342d969e17fc2d6edc856c59dbdbddd25f158fa40eaf043"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:514cf279b22fa1ae0bc08e143458c74ad3b56cd078b319464959685a35c53d5e"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a647c5b7cb896d6430cf3e01b4e9a2d77f719c84cefcef825d404830c2071da2"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cdf379219e1e1dd432091058dab325a2e6235ebb23e0aec8d0508567c90cd01"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ba72260449e16c4c2f6f3252823b059fbf2d31b32617e582003f2b18b415c39"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:910b96ed87316e4277b23c7bcaf667ce849c7cc379a453fa179e7e09290eeb25"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53975a6694428a0586534cc1354b2408d4e010a3103117f617cbb550299797c"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:07c4b7be58da142b0730cc4e5fd66bb7bf6f57f4986ddda73833cd39efef8a01"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b605c540753e62199bf15cf69c333e934077ef2350262af2ccada46026f83d1c"}, - {file = "tokenizers-0.20.1-cp38-none-win32.whl", hash = "sha256:88b3bc76ab4db1ab95ead623d49c95205411e26302cf9f74203e762ac7e85685"}, - {file = "tokenizers-0.20.1-cp38-none-win_amd64.whl", hash = "sha256:d412a74cf5b3f68a90c615611a5aa4478bb303d1c65961d22db45001df68afcb"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a25dcb2f41a0a6aac31999e6c96a75e9152fa0127af8ece46c2f784f23b8197a"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a12c3cebb8c92e9c35a23ab10d3852aee522f385c28d0b4fe48c0b7527d59762"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02e18da58cf115b7c40de973609c35bde95856012ba42a41ee919c77935af251"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f326a1ac51ae909b9760e34671c26cd0dfe15662f447302a9d5bb2d872bab8ab"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b4872647ea6f25224e2833b044b0b19084e39400e8ead3cfe751238b0802140"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce6238a3311bb8e4c15b12600927d35c267b92a52c881ef5717a900ca14793f7"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57b7a8880b208866508b06ce365dc631e7a2472a3faa24daa430d046fb56c885"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a908c69c2897a68f412aa05ba38bfa87a02980df70f5a72fa8490479308b1f2d"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:da1001aa46f4490099c82e2facc4fbc06a6a32bf7de3918ba798010954b775e0"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c097390e2f0ed0a5c5d569e6669dd4e9fff7b31c6a5ce6e9c66a61687197de"}, - {file = "tokenizers-0.20.1-cp39-none-win32.whl", hash = "sha256:3d4d218573a3d8b121a1f8c801029d70444ffb6d8f129d4cca1c7b672ee4a24c"}, - {file = "tokenizers-0.20.1-cp39-none-win_amd64.whl", hash = "sha256:37d1e6f616c84fceefa7c6484a01df05caf1e207669121c66213cb5b2911d653"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48689da7a395df41114f516208d6550e3e905e1239cc5ad386686d9358e9cef0"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:712f90ea33f9bd2586b4a90d697c26d56d0a22fd3c91104c5858c4b5b6489a79"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:359eceb6a620c965988fc559cebc0a98db26713758ec4df43fb76d41486a8ed5"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d3caf244ce89d24c87545aafc3448be15870096e796c703a0d68547187192e1"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03b03cf8b9a32254b1bf8a305fb95c6daf1baae0c1f93b27f2b08c9759f41dee"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:218e5a3561561ea0f0ef1559c6d95b825308dbec23fb55b70b92589e7ff2e1e8"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:08aaa0d72bb65058e8c4b0455f61b840b156c557e2aca57627056624c3a93976"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:998700177b45f70afeb206ad22c08d9e5f3a80639dae1032bf41e8cbc4dada4b"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f7fbd3c2c38b179556d879edae442b45f68312019c3a6013e56c3947a4e648"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e87fca4f6bbf5cc67481b562147fe932f73d5602734de7dd18a8f2eee9c6dd"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:956f21d359ae29dd51ca5726d2c9a44ffafa041c623f5aa33749da87cfa809b9"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1fbbaf17a393c78d8aedb6a334097c91cb4119a9ced4764ab8cfdc8d254dc9f9"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ebe63e31f9c1a970c53866d814e35ec2ec26fda03097c486f82f3891cee60830"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:81970b80b8ac126910295f8aab2d7ef962009ea39e0d86d304769493f69aaa1e"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130e35e76f9337ed6c31be386e75d4925ea807055acf18ca1a9b0eec03d8fe23"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd28a8614f5c82a54ab2463554e84ad79526c5184cf4573bbac2efbbbcead457"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9041ee665d0fa7f5c4ccf0f81f5e6b7087f797f85b143c094126fc2611fec9d0"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:62eb9daea2a2c06bcd8113a5824af8ef8ee7405d3a71123ba4d52c79bb3d9f1a"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f861889707b54a9ab1204030b65fd6c22bdd4a95205deec7994dc22a8baa2ea4"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:89d5c337d74ea6e5e7dc8af124cf177be843bbb9ca6e58c01f75ea103c12c8a9"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0b7f515c83397e73292accdbbbedc62264e070bae9682f06061e2ddce67cacaf"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0305fc1ec6b1e5052d30d9c1d5c807081a7bd0cae46a33d03117082e91908c"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc611e6ac0fa00a41de19c3bf6391a05ea201d2d22b757d63f5491ec0e67faa"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5ffe0d7f7bfcfa3b2585776ecf11da2e01c317027c8573c78ebcb8985279e23"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e7edb8ec12c100d5458d15b1e47c0eb30ad606a05641f19af7563bc3d1608c14"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:de291633fb9303555793cc544d4a86e858da529b7d0b752bcaf721ae1d74b2c9"}, - {file = "tokenizers-0.20.1.tar.gz", hash = "sha256:84edcc7cdeeee45ceedb65d518fffb77aec69311c9c8e30f77ad84da3025f002"}, + {file = "tokenizers-0.21.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2"}, + {file = "tokenizers-0.21.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b177fb54c4702ef611de0c069d9169f0004233890e0c4c5bd5508ae05abf193"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b43779a269f4629bebb114e19c3fca0223296ae9fea8bb9a7a6c6fb0657ff8e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aeb255802be90acfd363626753fda0064a8df06031012fe7d52fd9a905eb00e"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8b09dbeb7a8d73ee204a70f94fc06ea0f17dcf0844f16102b9f414f0b7463ba"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:400832c0904f77ce87c40f1a8a27493071282f785724ae62144324f171377273"}, + {file = "tokenizers-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84ca973b3a96894d1707e189c14a774b701596d579ffc7e69debfc036a61a04"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:eb7202d231b273c34ec67767378cd04c767e967fda12d4a9e36208a34e2f137e"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:089d56db6782a73a27fd8abf3ba21779f5b85d4a9f35e3b493c7bbcbbf0d539b"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:c87ca3dc48b9b1222d984b6b7490355a6fdb411a2d810f6f05977258400ddb74"}, + {file = "tokenizers-0.21.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4145505a973116f91bc3ac45988a92e618a6f83eb458f49ea0790df94ee243ff"}, + {file = "tokenizers-0.21.0-cp39-abi3-win32.whl", hash = "sha256:eb1702c2f27d25d9dd5b389cc1f2f51813e99f8ca30d9e25348db6585a97e24a"}, + {file = "tokenizers-0.21.0-cp39-abi3-win_amd64.whl", hash = "sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c"}, + {file = "tokenizers-0.21.0.tar.gz", hash = "sha256:ee0894bf311b75b0c03079f33859ae4b2334d675d4e93f5a4132e1eae2834fe4"}, ] [package.dependencies] @@ -4787,39 +4725,69 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"] [[package]] name = "tomli" -version = "2.0.2" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "torch" -version = "2.5.0" +version = "2.5.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.8.0" files = [ - {file = "torch-2.5.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:7f179373a047b947dec448243f4e6598a1c960fa3bb978a9a7eecd529fbc363f"}, - {file = "torch-2.5.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:15fbc95e38d330e5b0ef1593b7bc0a19f30e5bdad76895a5cffa1a6a044235e9"}, - {file = "torch-2.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:f499212f1cffea5d587e5f06144630ed9aa9c399bba12ec8905798d833bd1404"}, - {file = "torch-2.5.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:c54db1fade17287aabbeed685d8e8ab3a56fea9dd8d46e71ced2da367f09a49f"}, - {file = "torch-2.5.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:499a68a756d3b30d10f7e0f6214dc3767b130b797265db3b1c02e9094e2a07be"}, - {file = "torch-2.5.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9f3df8138a1126a851440b7d5a4869bfb7c9cc43563d64fd9d96d0465b581024"}, - {file = "torch-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b81da3bdb58c9de29d0e1361e52f12fcf10a89673f17a11a5c6c7da1cb1a8376"}, - {file = "torch-2.5.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:ba135923295d564355326dc409b6b7f5bd6edc80f764cdaef1fb0a1b23ff2f9c"}, - {file = "torch-2.5.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:2dd40c885a05ef7fe29356cca81be1435a893096ceb984441d6e2c27aff8c6f4"}, - {file = "torch-2.5.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:bc52d603d87fe1da24439c0d5fdbbb14e0ae4874451d53f0120ffb1f6c192727"}, - {file = "torch-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea718746469246cc63b3353afd75698a288344adb55e29b7f814a5d3c0a7c78d"}, - {file = "torch-2.5.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6de1fd253e27e7f01f05cd7c37929ae521ca23ca4620cfc7c485299941679112"}, - {file = "torch-2.5.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:83dcf518685db20912b71fc49cbddcc8849438cdb0e9dcc919b02a849e2cd9e8"}, - {file = "torch-2.5.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:65e0a60894435608334d68c8811e55fd8f73e5bf8ee6f9ccedb0064486a7b418"}, - {file = "torch-2.5.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:38c21ff1bd39f076d72ab06e3c88c2ea6874f2e6f235c9450816b6c8e7627094"}, - {file = "torch-2.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:ce4baeba9804da5a346e210b3b70826f5811330c343e4fe1582200359ee77fe5"}, - {file = "torch-2.5.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:03e53f577a96e4d41aca472da8faa40e55df89d2273664af390ce1f570e885bd"}, + {file = "torch-2.5.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:71328e1bbe39d213b8721678f9dcac30dfc452a46d586f1d514a6aa0a99d4744"}, + {file = "torch-2.5.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:34bfa1a852e5714cbfa17f27c49d8ce35e1b7af5608c4bc6e81392c352dbc601"}, + {file = "torch-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:32a037bd98a241df6c93e4c789b683335da76a2ac142c0973675b715102dc5fa"}, + {file = "torch-2.5.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:23d062bf70776a3d04dbe74db950db2a5245e1ba4f27208a87f0d743b0d06e86"}, + {file = "torch-2.5.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:de5b7d6740c4b636ef4db92be922f0edc425b65ed78c5076c43c42d362a45457"}, + {file = "torch-2.5.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:340ce0432cad0d37f5a31be666896e16788f1adf8ad7be481196b503dad675b9"}, + {file = "torch-2.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:603c52d2fe06433c18b747d25f5c333f9c1d58615620578c326d66f258686f9a"}, + {file = "torch-2.5.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:31f8c39660962f9ae4eeec995e3049b5492eb7360dd4f07377658ef4d728fa4c"}, + {file = "torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ed231a4b3a5952177fafb661213d690a72caaad97d5824dd4fc17ab9e15cec03"}, + {file = "torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:3f4b7f10a247e0dcd7ea97dc2d3bfbfc90302ed36d7f3952b0008d0df264e697"}, + {file = "torch-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:73e58e78f7d220917c5dbfad1a40e09df9929d3b95d25e57d9f8558f84c9a11c"}, + {file = "torch-2.5.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:8c712df61101964eb11910a846514011f0b6f5920c55dbf567bff8a34163d5b1"}, + {file = "torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:9b61edf3b4f6e3b0e0adda8b3960266b9009d02b37555971f4d1c8f7a05afed7"}, + {file = "torch-2.5.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1f3b7fb3cf7ab97fae52161423f81be8c6b8afac8d9760823fd623994581e1a3"}, + {file = "torch-2.5.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7974e3dce28b5a21fb554b73e1bc9072c25dde873fa00d54280861e7a009d7dc"}, + {file = "torch-2.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:46c817d3ea33696ad3b9df5e774dba2257e9a4cd3c4a3afbf92f6bb13ac5ce2d"}, + {file = "torch-2.5.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:8046768b7f6d35b85d101b4b38cba8aa2f3cd51952bc4c06a49580f2ce682291"}, ] [package.dependencies] @@ -4850,59 +4818,60 @@ optree = ["optree (>=0.12.0)"] [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = true python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] [[package]] name = "transformers" -version = "4.46.0" +version = "4.47.0" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" optional = true -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "transformers-4.46.0-py3-none-any.whl", hash = "sha256:e161268ae8bee315eb9e9b4c0b27f1bd6980f91e0fc292d75249193d339704c0"}, - {file = "transformers-4.46.0.tar.gz", hash = "sha256:3a9e2eb537094db11c3652334d281afa4766c0e5091c4dcdb454e9921bb0d2b7"}, + {file = "transformers-4.47.0-py3-none-any.whl", hash = "sha256:a8e1bafdaae69abdda3cad638fe392e37c86d2ce0ecfcae11d60abb8f949ff4d"}, + {file = "transformers-4.47.0.tar.gz", hash = "sha256:f8ead7a5a4f6937bb507e66508e5e002dc5930f7b6122a9259c37b099d0f3b19"}, ] [package.dependencies] filelock = "*" -huggingface-hub = ">=0.23.2,<1.0" +huggingface-hub = ">=0.24.0,<1.0" numpy = ">=1.17" packaging = ">=20.0" pyyaml = ">=5.1" regex = "!=2019.12.17" requests = "*" safetensors = ">=0.4.1" -tokenizers = ">=0.20,<0.21" +tokenizers = ">=0.21,<0.22" tqdm = ">=4.27" [package.extras] accelerate = ["accelerate (>=0.26.0)"] agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch"] -all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision"] audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] benchmark = ["optimum-benchmark (>=0.3.0)"] codecarbon = ["codecarbon (==1.2.0)"] deepspeed = ["accelerate (>=0.26.0)", "deepspeed (>=0.9.3)"] deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk (<=3.8.1)", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] -dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] -dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.20,<0.21)", "urllib3 (<2.0.0)"] -dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "libcst", "librosa", "nltk (<=3.8.1)", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.20,<0.21)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "nltk (<=3.8.1)", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.21,<0.22)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "libcst", "librosa", "nltk (<=3.8.1)", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.5.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (<=1.0.11)", "tokenizers (>=0.21,<0.22)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] ftfy = ["ftfy"] @@ -4928,12 +4897,12 @@ tf = ["keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow (>2.9,< tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] tiktoken = ["blobfile", "tiktoken"] -timm = ["timm (<=0.9.16)"] -tokenizers = ["tokenizers (>=0.20,<0.21)"] +timm = ["timm (<=1.0.11)"] +tokenizers = ["tokenizers (>=0.21,<0.22)"] torch = ["accelerate (>=0.26.0)", "torch"] torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] -torchhub = ["filelock", "huggingface-hub (>=0.23.2,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.20,<0.21)", "torch", "tqdm (>=4.27)"] +torchhub = ["filelock", "huggingface-hub (>=0.24.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.21,<0.22)", "torch", "tqdm (>=4.27)"] video = ["av (==9.2.0)"] vision = ["Pillow (>=10.0.1,<=15.0)"] @@ -5053,13 +5022,13 @@ crypto-eth-addresses = ["eth-hash[pycryptodome] (>=0.7.0)"] [[package]] name = "virtualenv" -version = "20.27.0" +version = "20.28.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" files = [ - {file = "virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655"}, - {file = "virtualenv-20.27.0.tar.gz", hash = "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2"}, + {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, + {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, ] [package.dependencies] @@ -5073,13 +5042,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "weaviate-client" -version = "4.9.0" +version = "4.9.6" description = "A python native Weaviate client" optional = true python-versions = ">=3.9" files = [ - {file = "weaviate_client-4.9.0-py3-none-any.whl", hash = "sha256:922a3a83c6946b6ea017d495af5980e90089f97004be4025a3d250a6c40ffaab"}, - {file = "weaviate_client-4.9.0.tar.gz", hash = "sha256:87b2995fd403f6106bd4cc8a9baa77280bdb95617ed6b9a60b0b34b5faeda999"}, + {file = "weaviate_client-4.9.6-py3-none-any.whl", hash = "sha256:1d3b551939c0f7314f25e417cbcf4cf34e7adf942627993eef36ae6b4a044673"}, + {file = "weaviate_client-4.9.6.tar.gz", hash = "sha256:56d67c40fc94b0d53e81e0aa4477baaebbf3646fbec26551df66e396a72adcb6"}, ] [package.dependencies] @@ -5094,172 +5063,167 @@ validators = "0.34.0" [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = true -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] name = "yarl" -version = "1.16.0" +version = "1.18.3" description = "Yet another URL library" optional = true python-versions = ">=3.9" files = [ - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32468f41242d72b87ab793a86d92f885355bcf35b3355aa650bfa846a5c60058"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:234f3a3032b505b90e65b5bc6652c2329ea7ea8855d8de61e1642b74b4ee65d2"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a0296040e5cddf074c7f5af4a60f3fc42c0237440df7bcf5183be5f6c802ed5"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6c14dd7c7c0badba48157474ea1f03ebee991530ba742d381b28d4f314d6f3"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b140e532fe0266003c936d017c1ac301e72ee4a3fd51784574c05f53718a55d8"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:019f5d58093402aa8f6661e60fd82a28746ad6d156f6c5336a70a39bd7b162b9"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c42998fd1cbeb53cd985bff0e4bc25fbe55fd6eb3a545a724c1012d69d5ec84"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7c30fb38c300fe8140df30a046a01769105e4cf4282567a29b5cdb635b66c4"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e49e0fd86c295e743fd5be69b8b0712f70a686bc79a16e5268386c2defacaade"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b9ca7b9147eb1365c8bab03c003baa1300599575effad765e0b07dd3501ea9af"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27e11db3f1e6a51081a981509f75617b09810529de508a181319193d320bc5c7"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8994c42f4ca25df5380ddf59f315c518c81df6a68fed5bb0c159c6cb6b92f120"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:542fa8e09a581bcdcbb30607c7224beff3fdfb598c798ccd28a8184ffc18b7eb"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2bd6a51010c7284d191b79d3b56e51a87d8e1c03b0902362945f15c3d50ed46b"}, - {file = "yarl-1.16.0-cp310-cp310-win32.whl", hash = "sha256:178ccb856e265174a79f59721031060f885aca428983e75c06f78aa24b91d929"}, - {file = "yarl-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe8bba2545427418efc1929c5c42852bdb4143eb8d0a46b09de88d1fe99258e7"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d8643975a0080f361639787415a038bfc32d29208a4bf6b783ab3075a20b1ef3"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:676d96bafc8c2d0039cea0cd3fd44cee7aa88b8185551a2bb93354668e8315c2"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9525f03269e64310416dbe6c68d3b23e5d34aaa8f47193a1c45ac568cecbc49"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b37d5ec034e668b22cf0ce1074d6c21fd2a08b90d11b1b73139b750a8b0dd97"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f32c4cb7386b41936894685f6e093c8dfaf0960124d91fe0ec29fe439e201d0"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b8e265a0545637492a7e12fd7038370d66c9375a61d88c5567d0e044ded9202"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:789a3423f28a5fff46fbd04e339863c169ece97c827b44de16e1a7a42bc915d2"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1d1f45e3e8d37c804dca99ab3cf4ab3ed2e7a62cd82542924b14c0a4f46d243"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:621280719c4c5dad4c1391160a9b88925bb8b0ff6a7d5af3224643024871675f"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed097b26f18a1f5ff05f661dc36528c5f6735ba4ce8c9645e83b064665131349"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2f1fe2b2e3ee418862f5ebc0c0083c97f6f6625781382f828f6d4e9b614eba9b"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:87dd10bc0618991c66cee0cc65fa74a45f4ecb13bceec3c62d78ad2e42b27a16"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4199db024b58a8abb2cfcedac7b1292c3ad421684571aeb622a02f242280e8d6"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:99a9dcd4b71dd5f5f949737ab3f356cfc058c709b4f49833aeffedc2652dac56"}, - {file = "yarl-1.16.0-cp311-cp311-win32.whl", hash = "sha256:a9394c65ae0ed95679717d391c862dece9afacd8fa311683fc8b4362ce8a410c"}, - {file = "yarl-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b9101f528ae0f8f65ac9d64dda2bb0627de8a50344b2f582779f32fda747c1d"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4ffb7c129707dd76ced0a4a4128ff452cecf0b0e929f2668ea05a371d9e5c104"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1a5e9d8ce1185723419c487758d81ac2bde693711947032cce600ca7c9cda7d6"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d743e3118b2640cef7768ea955378c3536482d95550222f908f392167fe62059"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26768342f256e6e3c37533bf9433f5f15f3e59e3c14b2409098291b3efaceacb"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1b0796168b953bca6600c5f97f5ed407479889a36ad7d17183366260f29a6b9"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858728086914f3a407aa7979cab743bbda1fe2bdf39ffcd991469a370dd7414d"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5570e6d47bcb03215baf4c9ad7bf7c013e56285d9d35013541f9ac2b372593e7"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66ea8311422a7ba1fc79b4c42c2baa10566469fe5a78500d4e7754d6e6db8724"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:649bddcedee692ee8a9b7b6e38582cb4062dc4253de9711568e5620d8707c2a3"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a91654adb7643cb21b46f04244c5a315a440dcad63213033826549fa2435f71"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b439cae82034ade094526a8f692b9a2b5ee936452de5e4c5f0f6c48df23f8604"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:571f781ae8ac463ce30bacebfaef2c6581543776d5970b2372fbe31d7bf31a07"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa7943f04f36d6cafc0cf53ea89824ac2c37acbdb4b316a654176ab8ffd0f968"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3"}, - {file = "yarl-1.16.0-cp312-cp312-win32.whl", hash = "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67"}, - {file = "yarl-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36"}, - {file = "yarl-1.16.0-cp313-cp313-win32.whl", hash = "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b"}, - {file = "yarl-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab2b2ac232110a1fdb0d3ffcd087783edd3d4a6ced432a1bf75caf7b7be70916"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f8713717a09acbfee7c47bfc5777e685539fefdd34fa72faf504c8be2f3df4e"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdcffe1dbcb4477d2b4202f63cd972d5baa155ff5a3d9e35801c46a415b7f71a"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a91217208306d82357c67daeef5162a41a28c8352dab7e16daa82e3718852a7"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ab3ed42c78275477ea8e917491365e9a9b69bb615cb46169020bd0aa5e2d6d3"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:707ae579ccb3262dfaef093e202b4c3fb23c3810e8df544b1111bd2401fd7b09"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7a852d1cd0b8d8b37fc9d7f8581152add917a98cfe2ea6e241878795f917ae"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3f1cc3d3d4dc574bebc9b387f6875e228ace5748a7c24f49d8f01ac1bc6c31b"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5ff96da263740779b0893d02b718293cc03400c3a208fc8d8cd79d9b0993e532"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3d375a19ba2bfe320b6d873f3fb165313b002cef8b7cc0a368ad8b8a57453837"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:62c7da0ad93a07da048b500514ca47b759459ec41924143e2ddb5d7e20fd3db5"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:147b0fcd0ee33b4b5f6edfea80452d80e419e51b9a3f7a96ce98eaee145c1581"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:504e1fe1cc4f170195320eb033d2b0ccf5c6114ce5bf2f617535c01699479bca"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bdcf667a5dec12a48f669e485d70c54189f0639c2157b538a4cffd24a853624f"}, - {file = "yarl-1.16.0-cp39-cp39-win32.whl", hash = "sha256:e9951afe6557c75a71045148890052cb942689ee4c9ec29f5436240e1fcc73b7"}, - {file = "yarl-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d7aaa8ff95d0840e289423e7dc35696c2b058d635f945bf05b5cd633146b027"}, - {file = "yarl-1.16.0-py3-none-any.whl", hash = "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3"}, - {file = "yarl-1.16.0.tar.gz", hash = "sha256:b6f687ced5510a9a2474bbae96a4352e5ace5fa34dc44a217b0537fec1db00b4"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] @@ -5269,13 +5233,13 @@ propcache = ">=0.2.0" [[package]] name = "zipp" -version = "3.20.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -5303,4 +5267,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = "^3.9.0" -content-hash = "0c52f5ece4b6b909273fbdc9afa3baaa088db66e9f0be3f4926c4482400b618c" +content-hash = "eb706cb5d3d47a4d3ac32bc7f228bda27de77c87398999d1e610552ff19af93f" diff --git a/pyproject.toml b/pyproject.toml index e6c5f2d3..6007709d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ llama-index = {version = "^0.10.55", optional = true } openai = {version = "^1.51.1", optional = true } anthropic = { version = "^0.36.0", optional = true} sentence-transformers = {version = "^3.0.0", optional = true } +json-repair = "^0.30.2" [tool.poetry.group.dev.dependencies] urllib3 = "<2" diff --git a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py b/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py index 1fe49465..225b4c0f 100644 --- a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py +++ b/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py @@ -19,9 +19,10 @@ import enum import json import logging -import re from datetime import datetime -from typing import Any, List, Optional, Union +from typing import Any, List, Optional, Union, cast + +import json_repair from pydantic import ValidationError, validate_call @@ -36,6 +37,7 @@ TextChunks, ) from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.experimental.pipeline.exceptions import InvalidJSONError from neo4j_graphrag.generation.prompts import ERExtractionTemplate, PromptTemplate from neo4j_graphrag.llm import LLMInterface @@ -100,28 +102,15 @@ def balance_curly_braces(json_string: str) -> str: return "".join(fixed_json) -def fix_invalid_json(invalid_json_string: str) -> str: - # Fix missing quotes around field names - invalid_json_string = re.sub( - r"([{,]\s*)(\w+)(\s*:)", r'\1"\2"\3', invalid_json_string - ) - - # Fix missing quotes around string values, correctly ignoring null, true, false, and numeric values - invalid_json_string = re.sub( - r"(?<=:\s)(?!(null|true|false|\d+\.?\d*))([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=[,}])", - r'"\2"', - invalid_json_string, - ) - - # Correct the specific issue: remove trailing commas within arrays or objects before closing braces or brackets - invalid_json_string = re.sub(r",\s*(?=[}\]])", "", invalid_json_string) +def fix_invalid_json(raw_json: str) -> str: + repaired_json = json_repair.repair_json(raw_json) + repaired_json = cast(str, repaired_json).strip() - # Normalize excessive curly braces - invalid_json_string = re.sub(r"{{+", "{", invalid_json_string) - invalid_json_string = re.sub(r"}}+", "}", invalid_json_string) - - # Balance curly braces - return balance_curly_braces(invalid_json_string) + if repaired_json == '""': + raise InvalidJSONError("JSON repair resulted in an empty or invalid JSON.") + if not repaired_json: + raise InvalidJSONError("JSON repair resulted in an empty string.") + return repaired_json class EntityRelationExtractor(Component, abc.ABC): @@ -223,24 +212,18 @@ async def extract_for_chunk( ) llm_result = await self.llm.ainvoke(prompt) try: - result = json.loads(llm_result.content) - except json.JSONDecodeError: - logger.info( - f"LLM response is not valid JSON {llm_result.content} for chunk_index={chunk.index}. Trying to fix it." - ) - fixed_content = fix_invalid_json(llm_result.content) - try: - result = json.loads(fixed_content) - except json.JSONDecodeError as e: - if self.on_error == OnError.RAISE: - raise LLMGenerationError( - f"LLM response is not valid JSON {fixed_content}: {e}" - ) - else: - logger.error( - f"LLM response is not valid JSON {llm_result.content} for chunk_index={chunk.index}" - ) - result = {"nodes": [], "relationships": []} + llm_generated_json = fix_invalid_json(llm_result.content) + result = json.loads(llm_generated_json) + except (json.JSONDecodeError, InvalidJSONError) as e: + if self.on_error == OnError.RAISE: + raise LLMGenerationError( + f"LLM response is not valid JSON {llm_result.content}: {e}" + ) + else: + logger.error( + f"LLM response is not valid JSON {llm_result.content} for chunk_index={chunk.index}" + ) + result = {"nodes": [], "relationships": []} try: chunk_graph = Neo4jGraph(**result) except ValidationError as e: diff --git a/src/neo4j_graphrag/experimental/pipeline/exceptions.py b/src/neo4j_graphrag/experimental/pipeline/exceptions.py index 3f1419dc..713f6cb6 100644 --- a/src/neo4j_graphrag/experimental/pipeline/exceptions.py +++ b/src/neo4j_graphrag/experimental/pipeline/exceptions.py @@ -31,3 +31,9 @@ class PipelineStatusUpdateError(Neo4jGraphRagError): """Raises when trying an invalid change of state (e.g. DONE => DOING)""" pass + + +class InvalidJSONError(Neo4jGraphRagError): + """Raised when JSON repair fails to produce valid JSON.""" + + pass diff --git a/src/neo4j_graphrag/generation/prompts.py b/src/neo4j_graphrag/generation/prompts.py index 3c4d380d..365d74c0 100644 --- a/src/neo4j_graphrag/generation/prompts.py +++ b/src/neo4j_graphrag/generation/prompts.py @@ -174,7 +174,11 @@ class ERExtractionTemplate(PromptTemplate): Do respect the source and target node types for relationship and the relationship direction. -Do not return any additional information other than the JSON in it. +Make sure you adhere to the following rules to produce valid JSON objects: +- Do not return any additional information other than the JSON in it. +- Omit any backticks around the JSON - simply output the JSON on its own. +- The JSON object must not wrapped into a list - it is its own JSON object. +- Property names must be enclosed in double quotes Examples: {examples} diff --git a/src/neo4j_graphrag/llm/mistralai_llm.py b/src/neo4j_graphrag/llm/mistralai_llm.py index bbdcc4db..a9f88aea 100644 --- a/src/neo4j_graphrag/llm/mistralai_llm.py +++ b/src/neo4j_graphrag/llm/mistralai_llm.py @@ -84,10 +84,11 @@ def invoke(self, input: str) -> LLMResponse: messages=self.get_messages(input), **self.model_params, ) - if response is None or response.choices is None or not response.choices: - content = "" - else: - content = response.choices[0].message.content or "" + content: str = "" + if response and response.choices: + possible_content = response.choices[0].message.content + if isinstance(possible_content, str): + content = possible_content return LLMResponse(content=content) except SDKError as e: raise LLMGenerationError(e) @@ -111,10 +112,11 @@ async def ainvoke(self, input: str) -> LLMResponse: messages=self.get_messages(input), **self.model_params, ) - if response is None or response.choices is None or not response.choices: - content = "" - else: - content = response.choices[0].message.content or "" + content: str = "" + if response and response.choices: + possible_content = response.choices[0].message.content + if isinstance(possible_content, str): + content = possible_content return LLMResponse(content=content) except SDKError as e: raise LLMGenerationError(e) diff --git a/tests/unit/experimental/components/test_entity_relation_extractor.py b/tests/unit/experimental/components/test_entity_relation_extractor.py index 1ec56153..29ba6568 100644 --- a/tests/unit/experimental/components/test_entity_relation_extractor.py +++ b/tests/unit/experimental/components/test_entity_relation_extractor.py @@ -15,7 +15,7 @@ from __future__ import annotations import json -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch import pytest from neo4j_graphrag.exceptions import LLMGenerationError @@ -31,6 +31,7 @@ TextChunk, TextChunks, ) +from neo4j_graphrag.experimental.pipeline.exceptions import InvalidJSONError from neo4j_graphrag.llm import LLMInterface, LLMResponse @@ -144,16 +145,17 @@ async def test_extractor_llm_ainvoke_failed() -> None: @pytest.mark.asyncio -async def test_extractor_llm_badly_formatted_json() -> None: +async def test_extractor_llm_unfixable_json() -> None: llm = MagicMock(spec=LLMInterface) llm.ainvoke.return_value = LLMResponse( - content='{"nodes": [{"id": "0", "label": "Person", "properties": {}}], "relationships": [}' + content='{"nodes": [{"id": "0", "label": "Person", "properties": {}}], "relationships": }' ) extractor = LLMEntityRelationExtractor( llm=llm, ) chunks = TextChunks(chunks=[TextChunk(text="some text", index=0)]) + with pytest.raises(LLMGenerationError): await extractor.run(chunks=chunks) @@ -177,7 +179,7 @@ async def test_extractor_llm_invalid_json() -> None: @pytest.mark.asyncio -async def test_extractor_llm_badly_formatted_json_do_not_raise() -> None: +async def test_extractor_llm_badly_formatted_json_gets_fixed() -> None: llm = MagicMock(spec=LLMInterface) llm.ainvoke.return_value = LLMResponse( content='{"nodes": [{"id": "0", "label": "Person", "properties": {}}], "relationships": [}' @@ -190,7 +192,11 @@ async def test_extractor_llm_badly_formatted_json_do_not_raise() -> None: ) chunks = TextChunks(chunks=[TextChunk(text="some text", index=0)]) res = await extractor.run(chunks=chunks) - assert res.nodes == [] + + assert len(res.nodes) == 1 + assert res.nodes[0].label == "Person" + assert res.nodes[0].properties == {"chunk_index": 0} + assert res.nodes[0].embedding_properties is None assert res.relationships == [] @@ -205,6 +211,14 @@ async def test_extractor_custom_prompt() -> None: llm.ainvoke.assert_called_once_with("this is my prompt") +def test_fix_invalid_json_empty_result() -> None: + json_string = "invalid json" + + with patch("json_repair.repair_json", return_value=""): + with pytest.raises(InvalidJSONError): + fix_invalid_json(json_string) + + def test_fix_unquoted_keys() -> None: json_string = '{name: "John", age: "30"}' expected_result = '{"name": "John", "age": "30"}' From b2ba9a30886859457b9eb32a3406d43145c2b0d7 Mon Sep 17 00:00:00 2001 From: Estelle Scifo Date: Thu, 12 Dec 2024 10:40:09 +0100 Subject: [PATCH 2/5] Document extra dependencies (#232) * Add documentation for the "extra" dependency groups * Use multiline strings instead of mixing '' and "" --- README.md | 26 ++++++++++++++++ docs/source/api.rst | 2 +- docs/source/index.rst | 30 +++++++++++++++++++ src/neo4j_graphrag/embeddings/cohere.py | 4 +-- src/neo4j_graphrag/embeddings/mistral.py | 4 +-- src/neo4j_graphrag/embeddings/openai.py | 4 +-- .../embeddings/sentence_transformers.py | 4 +-- src/neo4j_graphrag/embeddings/vertexai.py | 4 +-- src/neo4j_graphrag/llm/anthropic_llm.py | 4 +-- src/neo4j_graphrag/llm/cohere_llm.py | 4 +-- src/neo4j_graphrag/llm/mistralai_llm.py | 4 +-- src/neo4j_graphrag/llm/openai_llm.py | 4 +-- src/neo4j_graphrag/llm/vertexai_llm.py | 4 +-- 13 files changed, 77 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 2c5cd53b..9fb37a0e 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,32 @@ pip install neo4j-graphrag ### Optional Dependencies +This package has some optional features that can be enabled using +the extra dependencies described below: + +- LLM providers (at least one is required for RAG and KG Builder Pipeline): + - **openai**: LLMs from OpenAI (including AzureOpenAI) + - **google**: LLMs from Vertex AI + - **cohere**: LLMs from Cohere + - **anthropic**: LLMs from Anthropic + - **mistralai**: LLMs from MistralAI +- **sentence-transformers** : to use embeddings from the `sentence-transformers` Python package +- Vector database (to use :ref:`External Retrievers`): + - **weaviate**: store vectors in Weaviate + - **pinecone**: store vectors in Pinecone + - **qdrant**: store vectors in Qdrant +- **experimental**: experimental features such as the Knowledge Graph creation pipelines. + - Warning: this dependency group requires `pygraphviz`. See below for installation instructions. + + +Install package with optional dependencies with (for instance): + +```shell +pip install "neo4j-graphrag[openai]" +# or +pip install "neo4j-graphrag[openai, experimental]" +``` + #### pygraphviz `pygraphviz` is used for visualizing pipelines. diff --git a/docs/source/api.rst b/docs/source/api.rst index 68a0884a..d1b1066d 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -416,7 +416,7 @@ FilterValidationError EmbeddingsGenerationError -======================== +========================= .. autoclass:: neo4j_graphrag.exceptions.EmbeddingsGenerationError :show-inheritance: diff --git a/docs/source/index.rst b/docs/source/index.rst index df94a066..9d6f9a3d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -72,6 +72,36 @@ To install the latest stable version, use: It is always recommended to install python packages for user space in a virtual environment. +********************* +Optional Dependencies +********************* + +Extra dependencies can be installed with: + +.. code:: bash + + pip install "neo4j-graphrag[openai]" + # or + pip install "neo4j-graphrag[openai, experimental]" + + +List of extra dependencies: + +- LLM providers (at least one is required for RAG and KG Builder Pipeline): + - **openai**: LLMs from OpenAI (including AzureOpenAI) + - **google**: LLMs from Vertex AI + - **cohere**: LLMs from Cohere + - **anthropic**: LLMs from Anthropic + - **mistralai**: LLMs from MistralAI +- **sentence-transformers** : to use embeddings from the `sentence-transformers` Python package +- Vector database (to use :ref:`External Retrievers`): + - **weaviate**: store vectors in Weaviate + - **pinecone**: store vectors in Pinecone + - **qdrant**: store vectors in Qdrant +- **experimental**: experimental features such as the Knowledge Graph creation pipelines. + - Warning: this requires `pygraphviz`. Installation instructions can be found `here `_. + + ******** Examples ******** diff --git a/src/neo4j_graphrag/embeddings/cohere.py b/src/neo4j_graphrag/embeddings/cohere.py index 3289ee3f..63906a5e 100644 --- a/src/neo4j_graphrag/embeddings/cohere.py +++ b/src/neo4j_graphrag/embeddings/cohere.py @@ -28,8 +28,8 @@ class CohereEmbeddings(Embedder): def __init__(self, model: str = "", **kwargs: Any) -> None: if cohere is None: raise ImportError( - "Could not import cohere python client. " - "Please install it with `pip install cohere`." + """Could not import cohere python client. + Please install it with `pip install "neo4j-graphrag[cohere]"`.""" ) self.model = model self.client = cohere.Client(**kwargs) diff --git a/src/neo4j_graphrag/embeddings/mistral.py b/src/neo4j_graphrag/embeddings/mistral.py index 5a9c76a0..8c352263 100644 --- a/src/neo4j_graphrag/embeddings/mistral.py +++ b/src/neo4j_graphrag/embeddings/mistral.py @@ -39,8 +39,8 @@ class MistralAIEmbeddings(Embedder): def __init__(self, model: str = "mistral-embed", **kwargs: Any) -> None: if Mistral is None: raise ImportError( - "Could not import mistralai. " - "Please install it with `pip install mistralai`." + """Could not import mistralai. + Please install it with `pip install "neo4j-graphrag[mistralai]"`.""" ) api_key = kwargs.pop("api_key", None) if api_key is None: diff --git a/src/neo4j_graphrag/embeddings/openai.py b/src/neo4j_graphrag/embeddings/openai.py index 6204acb3..4a4d6038 100644 --- a/src/neo4j_graphrag/embeddings/openai.py +++ b/src/neo4j_graphrag/embeddings/openai.py @@ -36,8 +36,8 @@ def __init__(self, model: str = "text-embedding-ada-002", **kwargs: Any) -> None import openai except ImportError: raise ImportError( - "Could not import openai python client. " - "Please install it with `pip install openai`." + """Could not import openai python client. + Please install it with `pip install "neo4j-graphrag[openai]"`.""" ) self.openai = openai self.model = model diff --git a/src/neo4j_graphrag/embeddings/sentence_transformers.py b/src/neo4j_graphrag/embeddings/sentence_transformers.py index 3e0f9202..f30ed5b7 100644 --- a/src/neo4j_graphrag/embeddings/sentence_transformers.py +++ b/src/neo4j_graphrag/embeddings/sentence_transformers.py @@ -28,8 +28,8 @@ def __init__( import torch except ImportError: raise ImportError( - "Could not import sentence_transformers python package. " - "Please install it with `pip install sentence-transformers`." + """Could not import sentence_transformers python package. + Please install it with `pip install "neo4j-graphrag[sentence-transformers]"`.""" ) self.torch = torch self.np = np diff --git a/src/neo4j_graphrag/embeddings/vertexai.py b/src/neo4j_graphrag/embeddings/vertexai.py index c04c665e..5aecdcfa 100644 --- a/src/neo4j_graphrag/embeddings/vertexai.py +++ b/src/neo4j_graphrag/embeddings/vertexai.py @@ -36,8 +36,8 @@ class VertexAIEmbeddings(Embedder): def __init__(self, model: str = "text-embedding-004") -> None: if vertexai is None: raise ImportError( - "Could not import Vertex AI Python client. " - "Please install it with `pip install google-cloud-aiplatform`." + """Could not import Vertex AI Python client. + Please install it with `pip install "neo4j-graphrag[google]"`.""" ) self.vertexai_model = ( vertexai.language_models.TextEmbeddingModel.from_pretrained(model) diff --git a/src/neo4j_graphrag/llm/anthropic_llm.py b/src/neo4j_graphrag/llm/anthropic_llm.py index fd076c0f..e8f551cb 100644 --- a/src/neo4j_graphrag/llm/anthropic_llm.py +++ b/src/neo4j_graphrag/llm/anthropic_llm.py @@ -55,8 +55,8 @@ def __init__( import anthropic except ImportError: raise ImportError( - "Could not import Anthropic Python client. " - "Please install it with `pip install anthropic`." + """Could not import Anthropic Python client. + Please install it with `pip install "neo4j-graphrag[anthropic]"`.""" ) super().__init__(model_name, model_params) self.anthropic = anthropic diff --git a/src/neo4j_graphrag/llm/cohere_llm.py b/src/neo4j_graphrag/llm/cohere_llm.py index 6a6aa036..aeddafd3 100644 --- a/src/neo4j_graphrag/llm/cohere_llm.py +++ b/src/neo4j_graphrag/llm/cohere_llm.py @@ -53,8 +53,8 @@ def __init__( import cohere except ImportError: raise ImportError( - "Could not import cohere python client. " - "Please install it with `pip install cohere`." + """Could not import cohere python client. + Please install it with `pip install "neo4j-graphrag[cohere]"`.""" ) self.cohere = cohere diff --git a/src/neo4j_graphrag/llm/mistralai_llm.py b/src/neo4j_graphrag/llm/mistralai_llm.py index a9f88aea..b9254ffe 100644 --- a/src/neo4j_graphrag/llm/mistralai_llm.py +++ b/src/neo4j_graphrag/llm/mistralai_llm.py @@ -53,8 +53,8 @@ def __init__( """ if Mistral is None: raise ImportError( - "Could not import Mistral Python client. " - "Please install it with `pip install mistralai`." + """Could not import Mistral Python client. + Please install it with `pip install "neo4j-graphrag[mistralai]"`.""" ) super().__init__(model_name, model_params) api_key = kwargs.pop("api_key", None) diff --git a/src/neo4j_graphrag/llm/openai_llm.py b/src/neo4j_graphrag/llm/openai_llm.py index 04f3f2bf..9de5071f 100644 --- a/src/neo4j_graphrag/llm/openai_llm.py +++ b/src/neo4j_graphrag/llm/openai_llm.py @@ -50,8 +50,8 @@ def __init__( import openai except ImportError: raise ImportError( - "Could not import openai Python client. " - "Please install it with `pip install openai`." + """Could not import openai Python client. + Please install it with `pip install "neo4j-graphrag[openai]"`.""" ) self.openai = openai super().__init__(model_name, model_params) diff --git a/src/neo4j_graphrag/llm/vertexai_llm.py b/src/neo4j_graphrag/llm/vertexai_llm.py index b0820e62..dff5e1cf 100644 --- a/src/neo4j_graphrag/llm/vertexai_llm.py +++ b/src/neo4j_graphrag/llm/vertexai_llm.py @@ -59,8 +59,8 @@ def __init__( ): if GenerativeModel is None or ResponseValidationError is None: raise ImportError( - "Could not import Vertex AI Python client. " - "Please install it with `pip install google-cloud-aiplatform`." + """Could not import Vertex AI Python client. + Please install it with `pip install "neo4j-graphrag[google]"`.""" ) super().__init__(model_name, model_params) self.model = GenerativeModel(model_name=model_name, **kwargs) From ff6862ed93c373e1443925ac8c7c81e3b31ae94f Mon Sep 17 00:00:00 2001 From: Estelle Scifo Date: Thu, 12 Dec 2024 15:14:39 +0100 Subject: [PATCH 3/5] Pipeline from config file (#220) * SimpleKGPipeline config parser * Factorize common parmeters * Fix * Fix again (ruff) * Add builder, docstrings * Adds example * Ruff * Add headers * Another header * Remove old file - more detailed example * Fix JSON * WIP * Adds more param resolvers * A bit of mypy * Add root types to allow instantiation from python object directly * Document + mypy * Add embedder config * Implement SimpleKGBuilder with this setup * Add YAML config example * Example config files for custom pipeline * Update SimpleKGPipeline * Fix UT * Fix tests * Simplify and mypy * ruff * Add missing dep * Missing import for '|' annotations * Restructure files + increase tests coverage * mypy * Refactor examples * Test runner, clean simple kg builder test (remove duplicates) * E2E tests * Use fsspec in config reader * Changelog * Fix test * Use cast to remove a type ignore comment * Also use cast here to remove type ignore * Close instantiated drivers * ruff * Adding loggers * Make close function async * Fix tests * fix UT * Write doc about SimpleKGPipeline and config files * Update api.rst * Recreate lock file after merge * Add more comments to explain Config/Type models --- CHANGELOG.md | 1 + docs/source/api.rst | 45 +- docs/source/images/kg_builder_pipeline.png | Bin 139403 -> 152967 bytes docs/source/types.rst | 59 +++ docs/source/user_guide_kg_builder.rst | 497 +++++++++++++++++- docs/source/user_guide_rag.rst | 6 +- examples/README.md | 2 + .../simple_kg_pipeline_config.json | 112 ++++ .../simple_kg_pipeline_config.yaml | 63 +++ .../simple_kg_pipeline_from_config_file.py | 47 ++ .../from_config_files/pipeline_config.json | 68 +++ .../from_config_files/pipeline_config.yaml | 45 ++ .../pipeline_from_config_file.py | 40 ++ poetry.lock | 35 +- pyproject.toml | 1 + .../components/entity_relation_extractor.py | 1 - .../experimental/components/lexical_graph.py | 1 + .../experimental/components/schema.py | 21 + .../experimental/pipeline/config/__init__.py | 14 + .../experimental/pipeline/config/base.py | 62 +++ .../pipeline/config/config_reader.py | 85 +++ .../pipeline/config/object_config.py | 266 ++++++++++ .../pipeline/config/param_resolver.py | 60 +++ .../pipeline/config/pipeline_config.py | 199 +++++++ .../experimental/pipeline/config/runner.py | 132 +++++ .../config/template_pipeline/__init__.py | 20 + .../pipeline/config/template_pipeline/base.py | 63 +++ .../template_pipeline/simple_kg_builder.py | 228 ++++++++ .../experimental/pipeline/config/types.py | 26 + .../experimental/pipeline/kg_builder.py | 227 +------- .../experimental/pipeline/pipeline.py | 38 +- .../experimental/pipeline/types.py | 19 +- tests/e2e/conftest.py | 34 ++ .../data/config_files/pipeline_config.json | 72 +++ .../data/config_files/pipeline_config.yaml | 45 ++ .../simple_kg_pipeline_config.json | 64 +++ .../simple_kg_pipeline_config.yaml | 50 ++ tests/e2e/data/documents/harry_potter.pdf | Bin 0 -> 26810 bytes .../e2e/data/{ => documents}/harry_potter.txt | 0 tests/e2e/experimental/__init__.py | 0 tests/e2e/experimental/pipeline/__init__.py | 0 .../experimental/pipeline/config/__init__.py | 0 .../config/test_pipeline_runner_e2e.py | 208 ++++++++ tests/e2e/test_kg_builder_pipeline_e2e.py | 25 - tests/e2e/test_simplekgpipeline_e2e.py | 25 +- tests/unit/conftest.py | 6 + .../experimental/pipeline/config/__init__.py | 0 .../config/template_pipeline/__init__.py | 0 .../config/template_pipeline/test_base.py | 0 .../test_simple_kg_builder.py | 301 +++++++++++ .../experimental/pipeline/config/test_base.py | 37 ++ .../pipeline/config/test_object_config.py | 164 ++++++ .../pipeline/config/test_param_resolver.py | 56 ++ .../pipeline/config/test_pipeline_config.py | 378 +++++++++++++ .../pipeline/config/test_runner.py | 56 ++ .../experimental/pipeline/test_kg_builder.py | 268 +--------- 56 files changed, 3721 insertions(+), 551 deletions(-) create mode 100644 examples/build_graph/from_config_files/simple_kg_pipeline_config.json create mode 100644 examples/build_graph/from_config_files/simple_kg_pipeline_config.yaml create mode 100644 examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py create mode 100644 examples/customize/build_graph/pipeline/from_config_files/pipeline_config.json create mode 100644 examples/customize/build_graph/pipeline/from_config_files/pipeline_config.yaml create mode 100644 examples/customize/build_graph/pipeline/from_config_files/pipeline_from_config_file.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/__init__.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/base.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/config_reader.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/object_config.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/param_resolver.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/pipeline_config.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/runner.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/__init__.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/base.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py create mode 100644 src/neo4j_graphrag/experimental/pipeline/config/types.py create mode 100644 tests/e2e/data/config_files/pipeline_config.json create mode 100644 tests/e2e/data/config_files/pipeline_config.yaml create mode 100644 tests/e2e/data/config_files/simple_kg_pipeline_config.json create mode 100644 tests/e2e/data/config_files/simple_kg_pipeline_config.yaml create mode 100644 tests/e2e/data/documents/harry_potter.pdf rename tests/e2e/data/{ => documents}/harry_potter.txt (100%) create mode 100644 tests/e2e/experimental/__init__.py create mode 100644 tests/e2e/experimental/pipeline/__init__.py create mode 100644 tests/e2e/experimental/pipeline/config/__init__.py create mode 100644 tests/e2e/experimental/pipeline/config/test_pipeline_runner_e2e.py create mode 100644 tests/unit/experimental/pipeline/config/__init__.py create mode 100644 tests/unit/experimental/pipeline/config/template_pipeline/__init__.py create mode 100644 tests/unit/experimental/pipeline/config/template_pipeline/test_base.py create mode 100644 tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py create mode 100644 tests/unit/experimental/pipeline/config/test_base.py create mode 100644 tests/unit/experimental/pipeline/config/test_object_config.py create mode 100644 tests/unit/experimental/pipeline/config/test_param_resolver.py create mode 100644 tests/unit/experimental/pipeline/config/test_pipeline_config.py create mode 100644 tests/unit/experimental/pipeline/config/test_runner.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 7254d570..2ac264f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## Added - Integrated json-repair package to handle and repair invalid JSON generated by LLMs. - Introduced InvalidJSONError exception for handling cases where JSON repair fails. +- Ability to create a Pipeline or SimpleKGPipeline from a config file. See [the example](examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py). ## Changed - Updated LLM prompts to include stricter instructions for generating valid JSON. diff --git a/docs/source/api.rst b/docs/source/api.rst index d1b1066d..7d46b3f0 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -9,17 +9,18 @@ API Documentation Components ********** -KGWriter -======== +DataLoader +========== -.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.KGWriter - :members: run +.. autoclass:: neo4j_graphrag.experimental.components.pdf_loader.DataLoader + :members: run, get_document_metadata -Neo4jWriter -=========== -.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter - :members: run +PdfLoader +========= + +.. autoclass:: neo4j_graphrag.experimental.components.pdf_loader.PdfLoader + :members: run, load_file TextSplitter ============ @@ -85,6 +86,17 @@ LLMEntityRelationExtractor .. autoclass:: neo4j_graphrag.experimental.components.entity_relation_extractor.LLMEntityRelationExtractor :members: run +KGWriter +======== + +.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.KGWriter + :members: run + +Neo4jWriter +=========== + +.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter + :members: run SinglePropertyExactMatchResolver ================================ @@ -112,6 +124,23 @@ SimpleKGPipeline :members: run_async +************ +Config files +************ + + +SimpleKGPipelineConfig +====================== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.template_pipeline.simple_kg_builder.SimpleKGPipelineConfig + + +PipelineRunner +============== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.runner.PipelineRunner + + .. _retrievers-section: ********** diff --git a/docs/source/images/kg_builder_pipeline.png b/docs/source/images/kg_builder_pipeline.png index b8faf2bad32138aa2ce919461e466d3e560a6045..935c2a126792f940c373b7de7c3291de5c64d2bb 100644 GIT binary patch literal 152967 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%0A} zJ*#?a668S(QW^|pMPW^Vb0zME1hE3L0#vDo=2jd;j4O~G$ZLN2HJvtWO)f~xV zK3jHfI>4UO{=AhI%w@mGw1-o5D=xvm%z!1wuU+;>_i>&07|Nr5A!_&2dtAM%}o{REqn_Lsk{)R zx=%*Yr&Et&_wOzv32%O|NKV6Pf_TNvI9sP0Ife(FQ5Ml}wC8?iDY(BaSCeXL9fE{^ zq3SNj`@ZnIDAZ5;1V-?$ zm`KZIiUV4Z&$JwKLa{IaPZfj_Rd?iHZHKV%$Rx_y%?MgP`mkG>vL=C?0IIWI)ooK& zM*j%vd><=PE;L3Fx1=6}FW^3eJ0oaqAH-C}^Wo=H=8H?ixBT+noXOJRNRt&!(i?V` zw3uq5#Y&wF)l?O*mt_pmmYXEkeTbZ9FC|Qi;c{~eTt55xaHoPJxFqd&=I}zHzf{9= znJ6st)!|+!oFt*vAnGNGqWP)m1;ukc>=dL)NJyA;NaqoRQ29~O>hWP~4?sA8%uaxh zO~8m@a<~gZSC*p$p-kWIO)sbrB>m2FCz8DH#G+j@@BvPB)o*OFjxv6@1{s98`sV=a zWJL&<0Atr(CiBUxta&kCA*;%R0t9*lNB9`S91vjKB?=@h1kd4ZN31LzvmyKj@+qq`lV& zO4yY51=+MQW|Hpt4d$$x!z4(c-|XN^K_dbU^;OLW!^L(DUy^yTL1uXyF58sCBf_JG z*yPgO;k7G7YkZHW{jC1Rr#IDh!3O9u#%=ZH%Fg1wln6&E!|w!{=tj>jl|S3fiP5 zY6h_7dQ|Z9IRh3JAoLTkay}?4>nhPRR)azScy@*0 zu<%moV?r*f(Oz}wb5cf6CO&*0t^PH7<@L+A85#JgJ~9Tcod@I)Bpm9$7aPJswn7J`a1g8dHP~DKavV4TTrb!uDgU~L8N}QQ z$f4Ys?ryN{FlAI}{e9-Xqu`+&Fq|kPq@@clxzI{$0nk1vn46CvTrg5@lsWagS+|N6 z*3(N8T*=L?l z;TqYUm1)f8R__!g<^3D)TfqdbK7*W_kY>4Sj@_KXl%2HfMY^j{3L|6Sx09>jX6P0Qu%(DNdfct@!NR!EeUsl+^%auax_^VX+lB$!Obhv6wTjp6>3qjTOuM&Hf6m6 zZdJSlS2-Z>_DvMROb8p^_5d={aJz)UiW57U0u zRxQ{Ew~I+5n>lTsOhZK=?Hc(8uno%+^)$?*!5A@C-Yn3LD=cpHU@_Q!$2pIBgk$ue z20HJzLl&Sg&%;z6|9xF7yr3C~nv3sWb>U9W(MS}s^BhHmJY(F z&5W1cp2S!N%-0zzEa9n#)>Ge5moTrsLd!R)TeeK^c*$@fYpn9j44>Z19lOcW=bGeo zHIa|cow@Q1#nCXr+BA`VTbAF{aZ4i6lQ>vg?prZ~^8Pip0$hW@RZUr{)OGJD;nn zbQd-tUlEqQsBdX$F&=9_gUZGs=eHI`JPw>S`uibBnkwku4W=hBIt(b3KRr+g4TW9z zYb}5%6F?zK9M+vC_yO)EpRqB*@IW6j^pK`I>V%t{o6NIbsKjdl(x8PYGONE2#vwZT z6BDD1eIGa%VPN~~ORu*B!G-z36wZlmF`Hiy-en%wz-H0L=YWodAp`^4`&z%x!j7zP zFtr`~F7On>N#Pe}1XX~0i$#Bmv{mf*K!N3@{47<(R57s(%Ez^z5u8E?(H4`CH6AZv zc9aUZNE`wivt12mDH5r)`8j726l+mQy?|&+)CJKsiRqSo@}DI4f}0{KDk|DJ z2ABQRPR6q-^UOKf?P2rnujshj?-xyTi8FiR9tjmR)$X|sl%H~8G1z}SuRFJ>on74} ztF!)sKlZIn9`7UDOWWBxQ6h~ScHAxlFW1>UX7|=JtI;u>8-Dz;3l4X_$~2bq3>V^G zF+*syib^yop~WesEk zK8JMW+!SQCZqoH}!f3q&8uQ*)870!agLrv(VKp+Ev&+P~HLCx52biBff7U~^53pD4z3Khp@E%W$V@Ys4BxWMrSm>>Gx9o!dGTk0b|2}88 z1n;TmVaeMguG0bvunmONa9jRK6TqUcCR+oFv5nXh4>v7&^x z-2_#c{YvP3zlZ4FHK&`b-%9Doc6XEY_Q)UP?+^tsT-XpOTvp<{77CYn*W#%JaPzEl ztvny5$EwrwGLUt*jWyXH+%l50trsNnAIw(;=`6fUX1ZyjWA=iOE=eg{XStTfUsP(O z6SMJG(6vjUUpBKg$Yn6|%}F_(xTxxqa46=qCDOs(AbTVN=}QA1pdx86a4xNDOXR;c zGaaBWcP9+)ywLM&z3$VCg&y~c@a#DkG_9^18y8onAcAEe-H8ly=hPOTbB-gMvu0Woo){6^9k4V#T#VMOTgY;9y)Vzt1cBK7&B?%}qw(p} zN|(x`GR1d28wN4gd&ca3e}xO+!CBDcV8*-`rKG%mfK>xI z)xA6tv@_6jF?=L61K>GXCW>eBQ^gAffy8EC2bk;_+~idk@9#$VHf^Sp$n+d$xcrt^ zo&PSopflr%i<&3R?wJb$G;WMD80+;Vs;_KU%|9vk71D?<6E|Jv%-F1{cyhw*QJSL0 zscQ8+b`$lY4cAFc^x*ZFEOz(BSAb+9I4+XTx1sVB}}z9)>>Smb_A zS9mg^!#4G@1bdov4rVQH5T4wwOG5Sx?l(xhVbD}W*(fpvv>lclKhI*Qe?eNG9D}Cw zU~ck6dE`qs6xZXxcINaIdBZ4QFPG9NC@4Atwcvr3$%QhBd!*4F6=KLdNG?S>5F76|*gFeYJ=5$pvE^5inM0KEzFm7j4?&bkZMa73=`ebD zP-LzDK`A>?xs%qgIeJL=Gx@=}C>7R%mMihpZn+MuO0tHk^S$y^Lzpat1|7yvIi6vp z(fB9tE&*LI2&nouk<($+L$}uNgt+HM7{;>q(03$DO=_O9@{AV6en5w5VemNuCta3i+H4IO9BZ*?`2Al*=AY&Oj{0byK85 zs$;QpwS>pb!Uf^O!Bo3NNd$~~N+l*+t0#@HztDmH$&7??XLn;*9~get@Ru4zAr_UB zD}lQ-vay1bD?xjCvxbgk8_XG|PU}5Px&xEiivr8BsDWWs!+pVw4YLzsi(R=DvMnTW zyWE|bxWGhuMCwxoj1LqXu0E|)Hqk;?C0_Q^RxRK?*zd*ZIW-`wQ=KIE>EtH zx(|9GD!_apv+ApzOfS4jmT}Ikhsk`2kMM~F(Mn{JhJWXr zKYA_*J-n8mG`N_!(K9`~kM`Ls(1@G6Wd?i*cAP8~G9mOLcHS*#DASUlz!>@!$2B?s z9VIt~RW~V=5L71Y9AV?Dr*!JZpfuZy1LWvb5esNMf&`p6Bo@3k^=##8eq<+bm=Vg7 z*dIy&DETpUq*9(Q_*OhEB^e-ff8oY58TLX#;xc-X2|fPZ$1Q?n#rIurdEv{2l+9lj zz5bSQ;hGAJg6PRmr^-E{!SJ>oo2o&|wdc5=0n9;k=HmfqhWil?dM*9)$y zB^{ME#;C~m?}t+%72E~Es&4Gu##uGUPvY%=4Rb%M@*Vmw~%urNPrbCE((yiizN{JCqjI0B9!wIAMo8%J_jwlTPPX|c*i@f54x11C+!zdtRx7L6CAHJ)_;7vFjrfg z_zQIXS{9BxHVGeB+$9$isZ_;ukGw!Du#X>- z$KO#m>SA1`(+}ySTKjIOgbF9wI$FZJOheFzE8`3$O%&!4dGK$2!@nL~kkkkyaYAx( z=E$pai;I>P?qD-E-kzfQ`x%ei^a5;JB2%LbSuy%(IpAzV!~tM1LV(iN*3L2QVa*Ni zfuR`{LV|t%{Q3J2rpY-cDXxW^WPylm`8eUE(HSo&+-hOjS`*5)pQ}%tsromh2QQDD zw6*2I)}|)Wv9*L2^HT$h>zOs{f|KsoirpY`XKvHxe*=pSFC{x>H=&H8FVU)ID}JU? zy<469z4JPIdAsVwJ=;9Twl@~ibzJtf-Ky6$8h_1idnnDL%gt)q(doO_*)?-1WVhXP zo2fF~b>^7L-O2lE++DX9){5x8=WYq~uUe|_x=?4ZFHDg{-838fB3PrlZtfC?x#qJU zMhQ$7dgH#m1eY(aEC~aJiKhn6J@T8Fn=_@)ys>bJU9+QTW*d$4S02M?zqgq)>+bIE z_fPHaKiys25<~{7kadE0)bB&7Aw8N(UkN%j{tx?HSvOD@seX<{bLK2oaxXOn-3}E? z*?7)h&5Hx8Pl!f$3o)4^@GrQka_reCXWWPtiOr0Vxy_Zr!EDHPSQ;I*)raJ~BRU6C zM?XPD?yNxHQ4f$%lb>~VzU$`l3wl%tt9t(qvnrYyFM@Bn!QkLe|6qvc9YiKHwB@r< zF;m>Hdx|z%GpK{%m<0S|GBA^V@ZwM(7Pkle*ugJA#i-a_kFuTZtXsVYCR55lVI*|c zRXjW~(F{Mw<~eirYYA|q#u%97^sO{%ECz{y8tiH{D9D9Wx<#&19OQVRbF$-aNKFkw z*e(R(&rQA~`+me8{MVQH=kI-7Y?Q%w7H%N+eI)>Rx5LsN1(YCK*v`G6*lQJPJ{TJKn@2DJMQYp>AoET<^Ot& z0URiR%)^k0=_k80??GAmPMY%70a?sb7~e~xB05l{#-iSCDTLdY!}-~%x-5-H;lcVr z2%Kmu$8ixaw6(n`NzCsrvSl+8A2U~KyAN`|Yl9>1Yz?fQ8 zUO1ex4d00hXt~t%+`Jn}UJ5QHfOg4Iz;d_)&^b~|@vmcwba~RO#>zCQ_!hz(X$5gL zjYl2y?LWrRpMXvY0*4vn{LC0kAntdqn>{fO=~XMTj*!egLg62%R1Oah z)1v!tz%bp^y(OAI_s!+|w_q?8)~?NQ{oju=E9p7dMdk`KdxJq_qt$Cl5XJAIJo zym~Q_eDP#|@XbmAwVn-0P0)B6s{}_{m%mnhwPm$lZyu?IxHpmFgh}7vvO!bYva(xE z(9j3`DC;RQnty-Ke?Pu|dnt~Al>k~K*-SNCLwk>iEl8W9KO9a55C4p(04@TTfd{K9 zkqR>F0jj`{bM)*7$Ja5TvIVcDevgKicDmoKFO(%!5gWwf#6JAW^u~31y*52`yA|-b z)ij(^4M;YVF4kq$SzEUrN&fyHm-?Rv<~8=yXV2;YuA~RdDh$kL>fwmKwT}W$JTiEG zZCl0j$EOJAVD~aq!TCbCUm?t6zyB&6;_#wh(enb1GI!O>*aU2j)7m;nS%C6{?o^a2 zra3%K={u~x9zV@-SVH9bJ6otOb=8dr(1AQ&M~CMBJ{E_`_K%}NPQ>T5oCF8u4l;9j zcQ?jai{a9xOPkpW!9wX61D>LCG=n-eiA%1M?m2>do~OO5}({;aa3 z*f=YANN5zwJKO+m*L2sYN@fCLN0Jlp(dr1HFg2M_opn9FN; z?Ar0Z4n53mr4m|0FY$78hvhe?T*G(dulguT$LJ|#@-^0RNJ!CF#TL<%-F;RY!uTx7 zrs-At+=s@KeU57Sy)e7w_t+~H1jGiJjrpAZKa%#p()S;~^LmPlOojj+p-0H9PQ3-7 zo05nXbV8=-Z5k~=QvU_^XfRvL7eRBN*0&knLE@D(rY2#0XGEyoydgb+T&%5Ch6syGHhx10-#=QBQ^$% zSccjRhQLXn&3up|O}4bL;SfdiO8AeT_^^QeKi^Oq!|AhUY2l3Xo=Qg{Nz^F#vP$0j zBE@7Vn*fl*hv`Z6vEUt;EF}Sbt2;{Y%s;QVXAKU#75HD}XS>tq9@*&KI=B_xXO*_L z>G}#el}^SMGx=PiBkPX56Zl@8P74nF>bnfdExDd?>-1a8?oHC|WzM&K3I$U*=0RAN z1o~4#GP2FeFPwU{TC5yM8-%zGKso0t!gq+*{=Y)XKO)S?w*wR$CL0Yv^KNYERRNEM zaVWug<==o+5kwLMDm}r&qL>j4EX6M+HzS1p86*q+Jl#0v0YFa%4z2~!1+Rn8b_5EE zU6}q%B%bxU%2V>oZ>pHC0(A6u& z-hwb-4+tCLj8O30m-6t#&v7nj_Lc2NM&q0e)1_N>!~)#?F#Q4*pvg*5v^}u&Hs`anJuMsP;Batl@C ze<=(U^|jF0H0rs!x`J?>o&J98K^pzV6@0MS2DE_FfScL&NwA?q5OLWusRa8feqQ@uT>ECjRmn3T)uUt*bQ55l>y7p~zW! zuh$D2l&CLgs4V!noVNWSOEVzC-X2X4bua`99og-}z`#snh-dl*dVGGB5oaoESO}3Q zpJe>cpXvYc<%bxwO2~kFGWZ}#{0t%*0DMmp;Z6Xp!|kteP%?9OY4w0sd!Y<5XX3)LsK@W)_d>fBom*F@i?EH=-HECnHa-oj?;&Up+PKsjM4@+Fcnsq}VREDF1^7o2q&Mm8IEe?Gq5pcqPm8mA z!6l9o?S)Cy9pCTB2)?qi@;#<X{}Gjb zzu+q@S3yM|jBPrM^qk<=5&(`el7O7P9f|~D9hX_})npL^*FWMlWh4mjd7w=Nc8t%- z!&qfO^RuS;bVTk>={&!qdb5yntNEy8v#_`~)EX^6242=>DWBAM^N{z4q*cgcj@f5_ z8817k_?!%?k@wDzvqL(0c^g>oWesQ2M_6Y-oJka^UjRG^o4($A1_SzHVW!G*pcbFP z>;^`YQn21P%j2TISz-S?R=>a5(Z3rp@%s7GD){FX3=8jED27s%o}UL!aC@Q{9;p2} z7I}|63}&yAo%$m=Jy!&e4b}JesQQ32Tsn}8arjL$2z!gCKEixl!Ty9s7+x1{kxB1a z3Lm}Rvl9iYBhV8NlwST|@l4`pFqYnqRNr`njxqVQ;}>J_O^KjY4gl_8{bMXVJ$QN6 z+w0~&Ryr04fn*bwK8XeE!X?yl^Md5|g1-E#8DhN(JTMiH$Bn_?u4<_0Tf-aMl7}CUGbZ7#I&T)cQU=YK4^||2PmM_!z1jX3)Ot z!92csI_Uc0=Uct3e0@Vizkeq;XReaF=;0GRrFZe|FKTd=*vWWSyzoXH7}Op!O@-Ap z06!z{C#3r*9k7;;t81f^Kw-BIuvZKka!zVd+f{&p@Xs|$T9VJMy~8+ZK_ zW(P3EH^I|;kVZW5zhA$D|7wMY==LM)GtnBR1MeLdhHZQ$ zPGkP@)wCGEeIs2VJ#yMD|ENhB6w_+)GUb>F@a=RNld@DmzIQ0!;JA3OlD-QrXcMoLV4X zQ#@W-SqX*`qz)JcYxesQ#iN8$%A4#e9<-mqrbqH3JnLncGVznz=3@?vBV9 zo>4J_d^iOWomkNSgqzm@;)WgJhd_=X-dz+mTYyf_`uk_BmEjXIPi4bcV?Z7EX{VFc z>Hn{7h7;>Kg^i4OL0a`w_*oLvMGYgLo*)(C{owp>q82XNM=JJ~Pg?YU9PmddbcL>l z`=)-|)W1%_e&B`WZ{xv)jys`hAEPy?<(%AknCr5BSg$LyorHS#xW?IG0Z{78lA!CU z^jDJXv4@y~wIREj5o#=`0`ihK@lw|XqUl|;QHxT^!fI%q8295EK@CUVK8K?g-xv!AQ}jT9<-Xw6(Qv7lxqC! z6#btbh#f*El%bvn`c$G!BB+BVi?bBm^YaluHyEyythqqNsRuKN?ij(qKPqNLY&al@ zvFVD#$s=gl;SBc9w)d-W#|N*Yi&;pS#zVv_9{wOy$*I1{VV2Y8>{^4I57&{$NyRS1 zv{ifk*WL*Rc4VWTX++>}!|Shu&hKqZEfjyQls6T43&COvSziYB4Rk=Ca+|KxM4Ks- z@mfTWx5N#P?aO|~JcDpNe)7R)k9V@kFi1=6O8H-E5vc1yf`?DecaK%Q_^df9^5+&5 z)l##aZHgZ}08Y?{ippRB1PBQEgbrA0-O+;g|M>Pj$hXgbE)D(@Wd=jiXOZY%xr=p@ zqU?(1YXPc#%x|H-`YV#6CeT*yzdxfbiGu_^UkPu5uo1Wz@+HyBMm&Js33{yRRFBsM zzb%X7w=w9e@bHMeeKnnX0n%eIvFf~E|^q|k?J(_%gFzwFk;Wt!o{Tu39x2>r>6mVLi zzdFT~7|VjVr{kEeR~FC|q3R4uDyE>P3R!8`I$4yYMN&gJRF=ar51ugEjD=s#07N9Z zQQ>2FMiWptaFsD9)U5*UkWdV8eDqu6ZzAiMlt*kCL@@=WMz+@Gkb*ck&wZkv7-@kq zv9RiZ1v>%Zfi=Pm0O%wDqFKp&Z~m7E`8!rd)5LE)MX0wA?eZ;wTNsE`;IND1SEVrU zGTOmxrwI6FPO^)n$R1o9R3ho0MNI@2EU&%-qZT3-o-Vk~dKdkE9M*GIY9nz(y!w?6 zHRE5BuNJ9s6o3L;sY|@(j#UKM#BveA5A7IEa9L=F%p-x6!A2AZtg204FK1fk_K4X3+u;&1w$?!9Av3 zz$WVi(D1K74~(c(1)&cWg{LS;c59-`pV-T0|FgY%j)4KOmNps9+IM_%DUxT}$*W-H@vd_!)a({n+ z@*D1Ic^^~XE&y*S<<>m(BrH&_zqEs2iY4F{QY-{5oED}GL>1q%gpeglq!XMg1gOX| zXzV0`HI@Xx_JcH~Y)2+Z21CJBzkh;ce|&|%|3d&5V(1XXC=R^&wrlOCtzeK=G!7xE z83UJ;)okd3fPETh+i8uxvUvZf8Af!x5Nk>(LYs!USnUn@ki+8j3u{lvM%DS$w(4C? zf-olksi5r{!3qwu9Y!-R$V+-#Q#nZ|%UM3j?sZFjHN zWnFZQj)>gA)f03UYga3$Q~XH$M?nf-^fRbQQWjFP+gZ6-xsG*g8#G%K#R83tsW z><0&!J|M6ib4!v8sec%d4x;MB?SlH(Dj_yNpP^@0k^%aNC=o8CLKdj?LPx88RrMJ) zE*Of6KHYq~4(|>jcgq=bs~6h_G00w&Bgh9_-@=&FVvrBn5ED%p6i7TQnyDJAW*^H3oRhAa{{kZWcM%U46d@ zG1Ckz=JWwfY74+6VZMyOcU4x|=8h|qGIAL9a57Gn#$1u3=S<-w!ttjNpck;84*I3A8Y>E}S43MX8ibAciAYNcL zcFPO0QG|R9Vx0)-*w1Dh*f&vM5Z4VkAk~D=pP4NxgGE39fyN?+6vyjH?KC&^VDv;K|-Bt78V1u88T3@CDEe$o{wynFruf6i#7 zUauEMj!5O1NM^kJo<5X5A81Gow76fp!|30!!d@PTvT@VeKZYyV;6(<3eN_Vx#mHyx zFgYVGTZq#U!W$CV<|_`QmstloE;QLw)2xXh)(DvcWO@#cm$nJ)>=b0S2(YomJNM?# zstdP#05G8zvGRfJb#i6eDLF(5R_spwypHqD3L@+>5L6pt1RN3<`je$dHzB;gEh8Zz zp+{D`ne}E-b!*$MX{cud3iW{grrKB!UX=6RSF^~UB@kzydN-{9w+DK3IW1VPnsze> zV_#UgmZ$KzOH`>0E&W@3eVEfqZ&Gq`Jp^@xX^JFA8ZY^y$>;EAm83>KPn5KOuXIWik?4rF8uwj-8(`$NpXng0DRGpj*SIRyW8GT zzak$@_~gkGqAppG?@a(~BGp=M!V5xyTv;%GMW~91>T+zhP9`{QcXziM=*1s8U@K=H z|8d0l;$emJNdj`dR$9-R9&q$!MV8DWBfg7ntM_wdhe{vq*GQ&z&OZBE$VhPNJlC|> zqct6U7(3_zk&8YWGKK^w9}!5J-dK?+dqEZG5t}p`sf+`>GNHRbq8W=KT>R&O{5yC2 znOBv>wZOpxq^nO)Q2*$7=U)nIv`8Xx68@nx`zH8nc$9o;@2Bb7|a$?_6dY{s1^voCw;7 z=Q3xNEPu!L$>YZdgt`|V>{0YKi01gUE!;}rFyO-wVzN2rf}u`)Rm|?Nw|@PbKw!YD z0oOgQRlR9FQhE?s#O1PKk+@#4kklo_ozNYK24@jil`(cK$|PtSL`E?=*HY=tW-r;O zaIYd8QizS@iWfkfS8Tt)SiJQBssR}e8y)|sT{W%<2nEfAgoHukS6*M>y$hQ?$PI5q z+HL`|`a*#aosY2Hfn6X*)TWEp^w{lEGkV2zMxmfbHy2bjPNOdv5*ISIjpP;8(+j|t zVTs<2*Q9gW>x5=5_OAc=7Ito||2QW2(PVr3SG}||<--~INNh&2;+NRC&&AJR z+&{D9OFY3y*7qi_8Zp{xcicRZz(hfCi(&Zs66Bma=7g+Tw+dKeC6{D1DZG z0|~;f>EqGv9kpNYV}tVH^bTstup@c6HJxxOtG4f&ezgKM^)J#U+%v+IcTf{OJ9OO& zArtT3nH+aj%f_!V5%0<^{-{t0K+TO@f@UmcChEPLEe6rKvEHGClL=Cpy|qo zifrOi%sF*f*#e!`rubFk-d2C7O?YT%=p4J+sZOmq@cCi`i$m!|b$yKP zakCA88?&^SVoNvhmJtKe;Sa!7W`v@2`J+@DUC6#Uf1!0HbQM%8)ST~U`;S(a41|N5$`vyFLP{X%WS6ZwlRJ!zm=du zumPKHt`eKs^mDli!cLzylk~kvZ`dI72r8hamZupjshQ0AAun2~Z^F%3&+XA2xEF*id6l>(jdK8OObEXoSa=*oOf4-eRUZB@! zrk@r2yDga73-%=g^s73S1fOS{-v8Of3qK-mr50036Tbi#W{Xj47&4vkPuysUth(n@ z_Vp=M#zAVSuaasAy$ObLtLsnK#t0YXpPoa{kX1$ce zj1RHTu?4(dT3Sk>o`iC?tk_f>Tt2-u{7pwzHTSm^L$$?vo^U<=;8hN4WpRjNoN?_} zlaF7z0eUBxpv#6fl)=tZy}g}HWp6KTa>rq}4gI1F=(3`&L!Ztqf2->A=Wzg+kXo<~ zjGo*SsLNmjv>sUNDQ7GK2ech(**G_@bH(72`ohnTVEoOmg}0wNkiu}miJ%xr^8Hin zaDI7KOgiGH01{m6Xi==~=8snpj^Qzn?D?gF1Ng{~6qW3Xb&vfG55)Oy%BThEdv-5* z4|%t@iHXwHz3}HWJG=6Y@5y`2#PB^zj23iiHyuK@p&B$rPB;hwqP+gmDvipBKty1` zrbUPWaH!h0Sgyu&Vpp31#1aI-NC&=eaRPOKb?8?k3uDcH548wpKzhIOyH)t+r5>cW|B7omqzKB3*~>wZn?AZ&a32;cS=$yfkWTq#j;9lr-U zOvEqFps>%fd*wvE7MI=>S6*{|>*=5XZxmTsfn(&1E`85BE2UB8c7A!q490e=A4Na9 zA?``AOBZLF)}*VsVAx$15=)rA2ZbzCTL$nGEpJeWEWZ4Rq0o|&Ae~-5lPdWkcM+C8 z>bp}dD{3no%Y=4f<$MVsgY40 z#7sg&yKcv;q+VcZCtt=Hq=2$F-zxRyK1I$qVq=nivIMLp3Z_-Cy+82{lU8YpUSz!)YJx?C5(Ky~h}D2rkVuK0!iyj$rj+)J>! zBa)ZKrr&mdHvVFf@z(8knOD;lhCl{(+roSN+#kX1|Lk2LfMr3AzA}_M<(Ii8^r-Cn zD!5&_1S)*Z`=fdkw!%RI5@M5_d--$LCp!xz0;I{Ubn@aU>y|Y6ATE)iAlWWOp7#;SI%TmPA9J14GE=OWS2!52_&FRjl)y`l3tOXW&u zuJJFqjd3&c{yg>y>|*phW6TzA73{}NP3+P;W(*;(fd_km{7!1t$B@jFn-EHr{rh-Yyam+s+y}Y&%Q5J{k6AHksD%s#%+0-TX%-yf5>9!Gwm* zb+RiNCwmhhWm&?$GianUNrSvGAbp*^s&V(4$@C(WEo;}tp|0I1o|}eZJIY-C9zn?L zH%G}gmji?K!^_W)kaL^7K}raX8k4Lw$Pdj(al@{K~wI07nCCw{ogAR=XDrTI!)A;@pOQOY@rj z{Ir5lw+&^>)ii}4$fm^Jg>_H#SnB!o%wybUX~aHm+yp+R?^Q(J^>L@$Zo?+|IvC5A z7V}sPDserWPc_aTfCJ{NZ1k71NZuaf=dWMC*29`Q8WxqjtJ>BCYTLNhb8{_{-JuHgVHb$qfAWg0m10F$=is5=DzVFn`%Rk5&mNfZ8ltKIHCXEdk1Hw;Kw08i zW}G(U%M_=CY^MWSbP-d_$F&(D{(xDTXxzvkc3K+&xIf~wgGJ;V+j2$?8}#BC;HNu? zU&sDOfcnoOAIUsev;mQkCKi?Rn?prIYHF6R2Ma8RQ7Skce?r;Mq_n_SF0rS2DpdD~>j^Y+VICXYH-cO+E;& z2ytHW6rwF+uCAp$j?msMUGs>IxxO_`L&k5dhc<1?hRtT$9}^USmdk0Dep4YIrmi0p zvAg)+D@=BkK`k)O(#+$c9m{ zHRBne#aHcY;n_w23*2{=>bf3b6h3lvWztEsiY)Scyq`V-GbdB{*;_-ptwqeuo{`A* zvJN^72_zpKzr_95OdnTkf%~p=+i5)wbY31;(E@s49FXL-^Y*Y^Wf}065}{c6bKPX< z#?&?AtZv2dhpFi%UGi>K;1=e7{hcb9gLi@hYG!EA1mAh*uB$1A9h7f}LM|7`Jc)(+ zazoi~&HI8y0HW<&Y%Pbh!w*cTkBQ&a)61jOJFd+=2*!8G00MEbK;tJ_%X?Z!o5wi}jKxBpGTA)sFsRhW98Ss+h#>zlb zmco%^*zuPGjNNTY{h@xXgB`|`cF_vS=749tt{MC5e@Hnyq^)xdTtA(`%DbQr<`~9| zpMiYCvrqa7|Bo9dOhwW<9G6!c$n!bt*)P!?TlnmFY&`tEMTO255X1Lv*sfzy}W8WQ!_4@uFQD!MCN+Fw& zJ+diTmF!JqW|LiytW-u>AtaQ&_efMo8Of$p_J}enq2F~I=g>Ld^ZT4XIt@I}bHDHV zy07bXy50lI;%*p{g(Kxo$Yrk|o zT(Vh2uQE4@Ui2FKoSl#dgeSQWRTigW6xbxt|D?rv1+DMVfRNyvdFQUTi_ zI@85wpzMO}(^c2@`Qc1U#x9WX|DfsDJk(`qF4nD+%1=i}H&mSQ8%-qF$=B*fE~qeL zF|hlqw!Z)nK-mDRo)bBJqeWBSB@$7T??yzB&BdM)1uktz)jsHFB#aya9Eo`Rlo@2| z%aPW3ZyM)qFK@c0Y^B!(iPsGt=g1|4Y`_e9 zWof%YtgT@tz&L+i--^HS=TDzfV5|kI_O$biq&~_Ry;y%Kf1M$l4E-;9B+TH8#n=@= zbT&&@MU{(=MEA)#wp(0F*ir9@SgU{e5ltGL?fUJk>M@{2HlNAEnX;)aC=_1R4hg{q#kT_lAc`031$k9Z^?QQi^~e10$%+ zs{(+~$Tbqop2KbY8m|0~sh`L_7TP28R;;}tpY3R<<@NJTgcXUStgo(w4c!Dj6 zr&tZ7`-yf7>OdWenXuL~oB}B1E`-ayMV#F#%YE&YGf}{E?7zf+KKt2ZR_uEhaBQg| z7&p%ae4_x+$I_2{&vT5I;suE7tZ2ImQQTwVppic;?p4+wm%ZGl1u90@>f_;)>O!`<<{EC$%61CF=K4PeaeF@bKPN`dT!Ne-3I zTtu02(M3PrLUwfmm=_!dZqpR#8);c^)>QHof2HqDeK-2(Q=XsvC$ka8>}h|q8efx3 z9M~8Ww)0l~CnxM(SXpQC6lKfg61hb_IiUj=ZgSAgLZQ>rH#V_dz%DW>0eRu#u3HtM~ zgp-feCA@J1UCtBhfTt+$&{vv$fj|9KZbWMrgGi+jI31&3f6PA(t!A`%#4P~2|`g}kA){GX=w_u z9hK!5Gct2{KB{C7#deIcS51lp%&vk}6L99N@e!R-XSZ^T9k@>k9#* z%ua64#mSNRW22CWyb_p;4hu61=@cCVhP^BxLgZ}|?}pMeF1=y1$-LTE4hVwW*qjY@ z%e?vvo}?zZVQ6C{lXJn*$s~pnfk`PQ>}Ny(T^tM#ZE9)~|79)d0tfTp;lqc=4>}IE zx|`D(?&h-{=oxU3_g*cA>aGc*w<%D-u(G9O8o-GpT9NbX>aoUYNGE5UK~(wjoUUu6 zaj`<)8vVrbt<*7TWI@WC2H5X6pdCyUGZW{&Y-p$y^O-5`Ue4NcgrpJI`EA~lfYaXm z**sZT1Mvgtnm5wGyT<9TO6YH(4|!?mwpdLdf4(BC&R3a=vw3r#Q(Ihs_tj|bNQ-MX z_4Q*gwM$pRdj<`Pko5i3%Ne%s->%IaeviIF&`*c9P>|5Q=b%2=vC&r-O^+lR`% zdf8Py0mkaqKpa7Qnwz(7H9wykC@&nB7ND^RH zmI?7_P`yTOtlvNlz-4P&a*j2iRhI{aEi3kCe_Dpoy+4S*Ska!}ol5=6`HF{NC-^wk z&N}O`E+D%;ICNvCXNA9Hsw-ByOfl))?AGj1$e|YMw2F_`cfAint@{cE@Zj%3S0I)x zcP*q-A)Q)!$%ZMHEBbcLIj)f%@ms}EW+uj4#&lv|?%B=zf41mcu| zC-|8^qGk`k)c20`8;)ZwH#@1S-fcBTspkYZ=Y*uSB{o4`=SK7Bp%L-kv6P>MRxoZG zT`|4;My9GJr_QmT+S#z$aW(#hkT`Nei((I{UuPUiWyw@dWlNR00d#NU_rE%@a|4_t zN6u{)QcPDoPLxwbK)!I#;^QInc^Bd@S4sz&z^Nhv07zx1L@y{U_6VSGA(@9iEpB8|C`wSZd7r z0h?MlcdUS*e)6!L$5_hT+}!KW=uhPdU=v>Q>)ZE=HbYe)WK6kwfe@n#yMHn{_hw8? zjLq1q%zbNhX(B$bU6kcT1ra&W5qgiMGK+7{8;+f<{K_wsHRXK8D#b2KTW}I( zJpPu=GW8L|geu$f%jPfV@yLoKdwSJa^T#4mB10n1R7OPi&aSbN9?fNckjs8eN|E)h zu~v4E$I1@}VYm_T?U|UE6dWB3@RJQ3n;1=sbw;38;)^ukC(2A*tT!BaH9(-5uKHr- zu0426DuBb0>S(fIi0-F$eN>X-S)pGbAE=T`Bw*5y-cfq!_>c$}eoJ73u^;3nR0%g|6>BtKLG z)nRo;{^Y<~UEZ=t$7E*3)oxc9mfZ}A+ibB-Hd&T2@><IswA>WfBg)mN1REAnX{wc0e8O(eY9qP=SQIB^=2^T z$c9m@q&R`sQ%;ox593hN2%=~{#UO^R6Uqg%?E)OJ}VAA2TO>O64>cxwYzCgjxb zECHk$0ps^878L^7K_Z|#AthPA>zkUPYl#F$$J1n~ff4SqF#92@SIPvAI#jk==N4&LqjpqaS0_FG5 zpdx7gH7XL?zSlOJ8v_jtTJJJf)`Exie}kQ=!SkXK5l1VjS8tSjyGx?Lb>&O;1l3*16RJ zv*KD~UKQskH?(($<(?mgJ6L&9zZ(){!QPT9as8KI&3QY$E?v4*-Ibzl4&Va|0B$_3 zmWR}Lmx*~SG`26h#KV1A=6{!eWrE7f8@!&7VqUzVi>-kA2v?&3SRj4QIRTUE_+H0$ zv}KHWEUth_Z0(FOF|M_c5c3SO^ntvrca{#ZGq7zuJUpW6t@tg7U!9hd8!`1*{v)35 zM5@;x;|mQVkR&qAWpp1egXy`N$GWFZ{wdI+A2@bmnGew3*HVkI<98Wb zH7A#Wk+Kdvg0k-Zr<0p)d0%a#)-_XipT0zsQla754k||`nPIgNt+Szbh(^r{1#p5R zt}`;~C-0As%=04?)@0P6mg`~s>>PZ`&D^E@YpkPtMK?WZKxZCuzn&*!&V0tV@B~YR zSZ(rw-8Y_HQ^L6c%uoioqp8I`HYIwqC&9!M$F(?i)L)B{k@5ae())=syM5g|oxOF$ zG%}s7w0Ofx%v+C={&-hOZq`}!E&DyID}Z@SEa}F2hRTL#sF%QBMrO35f|HmrFfg!^ z1~J0jp`cNCOdYg@7+$t)&mi}W8@i%W-`L{t7(De2NL$i!8&F#vjNc;2NIk^i&S)L6 z@bA^NEoUSdJvH?ROMme9?)|62K9l6-%2{x0U0YiyEQAekqf6M*Dn-L8sy{6^A23}_ zm`0u0PbaiBi0q${bSqV2(ZB|XiXWrdYE8EwHUbbB89SlC*7%)`qd8o9-QagNu4xe( zv;wN2c;OMCQ}O0T9u;;>L8F1wk~(1a(>G7;+ndJ033ye%z8braJ*t2EMCxqsRc`G% zg)<5!FAh339w&@ozIPH28}AT?Bo3a~gUH5ubH-Gitcc(O`Q-#Rs)5JBMCFevw7eR= zbIRv7`Wf@`@T7qJ=f1iim;8$nqij5&>M5s#={$awm3ljSPMNgTyC>nA7jaI71eip_ z^j%2Q_>KX&v2_V?Y0d&vr$nNbdGqv{Gv=O3Ni+~9OxfZlxuo5xf;)eLcOK0}IsUe^ zt3e1@9EKYz0`UN|9)l1Wu_p_^AGR%%0%|GExIGimFCad~wcgmfKMID(y3u4}z3#WI zJW;6d1yU=!x-g1cj6?2@{q2ZUFt?uc`ho_*rBd{slb*}Mcf}_fX`PZY5H1q>&2U~I z`pP{J#VGm{kSjH6%*sZ_rBP7xv?#M*NcQ`w-A23RgtP-W_zP^!k9tBt;{;omu#*H@Gj>N9HtDP#0c)m+V4aB+G5;>G>C zvmV}j8{jaej^2J*sluyj*iO4@#ZOjNi&1Qlla3->F_(?~=Ex<}<|ZQHNE1Y)n_D04amv-c=@oTC~hg^|_cc&msg{|ka{jpZ$&y*n2uXUXafLj)qZYRPZDUNSZ zthwr)1$M1>!@|OZZ}Adk`ePQZ@}8hgm5bkun`9ao{=?^*Gm0OZy*T$6293&oYV8}2 zr7#<=Sc;Zcut~8w70-EiU+OE&kK1(>a$R>MF@#!gc^M|?)}0w;?ry3iO+V#Y1*i;V#^fCAP7$?=tL2yaOzc z`>)cLc}e9v5(UK?z=clm>9m!Lf#J+sMXp5;Qr@tyT&EMETz*A*?o{~9JDrou5Fq*0 zZ!AW8{}1Xo$t7%$XT=6;*|V1_OCT0CKmEOG_f*ig#mCg+k6Q_cp8MLGm-}S;8q#O zW{+d*qRc_06S*{Jh*}vbXYvOG1W+7eAuT7gFnbG1$~b}&WCZcC=SqLceXF#Z*gYrt zZ#QzCbN{6Peb@B#mW;9EnQ0PS2;&6^Ng6C4tTSFjfgC;g(Ie$Z&Fr;hh*ynJMQ}h; zUTvX1G#wkzT5M-*30{Z?i7$Bulp%H(boxlVNj2ChNmIBu%p+X>fA_c~H{R<6Fz%22aFwK+1~uPh;=+Bf?Qk7cNkwU$eaJT$2-DRFx4C!9oK&IIXEd#P6AH2Bldgsn)sJEbWriPJ-^0Uy zB=Z<>slx$xQ&dn0F0Y?LIX?6b8XJ0V&9*^PB^&>FT59UZAt{+xR8-~ctM9=Z9*tQE z8LNufYvKRduIA@UoNJ4V9-yp?%P0rQQcX;=iS2)d-}Pvm)P_IqnWIAtW&`E6*4^I? z7r#QSL0%!2Z?xlkleh_qsCb_H>FdV@7%yIyL(uEOMxLz~Q`*?KQE=jE4ORP}8J@Qb zZTfgA{ov8d;dA!4_^xQFvT5E9vlY~%XKX%$n1lrrK^h^-ksr>P>ZfoH-JA%L%p>Tb zIq3c4w%-F4a>ZC>9+Nr-K308`=F^SJGtJFUd?L9fU*XpqsQECRNixC(8VU;pMQ(Bf z!en5>Dk4ruI#9)=lp1zwrT#r{mtx3+Y@gH()c}JUomtwvKcV4r0(`~rlRFE@c7AX- zJmhYb;Ju_>`o;$;Oveso!JC7&(Ll697j*F6J(U|$z@cN9cYKvuE5a%@+TN;Nw&KSb zFJ&FHA`WlFyH!+Kal7b>flePE`w7p_Z_VBqS{67OW~}5%kW1hM-^;z2C~m+ z$ulqvRzr?Dq`sZp$d3e)Gt4Ird!}bhQ>D+FzfXNOTdWXb)fG{ylRjaRAN(%;z=>`> z{nI&?7j#roZf5nw(PyqH-7DVvjXCjReCuw{)@xYSjRQL(W9-%m(7^|P0 z`BJ{0!pu~wRY5gB<+RC-#|Hw46P%tYkg%M`AcYMYR}GCmOpgtvMp`vYyB&@G05yjq zwBu7D933PlS5Nw7%(LS${*iiY{1G!m5(839rC7cu>yuEvMS!c!o(6jD&AA4f zckkUxh0eciWv+T=)HD#NpuFS&w45uA$L8=xvSNoJs+7^ly>pLTqM_+kqKaZK&qLK3 z=d$U(M3y(y(aX$-bWgYFa1>Y>W~3jgoUo^kSWiGa0%Q~9qvl9&9`tBoI(U%Yq?tt5 zCWX(!Kx2<<4z2!S**&w%&|Nxiq1jLeO|TER5R&OY3>5{!NofJQ_ea{iG&0qp;3ga!lHn98{aox-yg78a5XZ?|TM|KCZpWReBJIBus7v4-8N={`2~4AYEfsN|P(`aHd^ z_4#YvSY)wv&OZi$xB)xxW-GwAP6@UfVY{u?=HL}v=CIhy(YYE&q7wxZ!)Ln_qfRd> z%DX+0TRY{f!loG%W}U-%r7qu+vCeEng8WkHQN}~M_U1wNR|te;P1b@*t?w$=ol7M3 zEK}zY2uz6zjUtGSis0;yh*WVoKKx4Iqg1H8Sx=IL90v);msDO}9?j`$22D06)RL%w zefHcrK|&S~TOr>Zn2T%oWzP$)3f!v(G5`N%z;ng&&egt=2ietCT`M@%NR4fv9_Z^W zk+suwf+YhR{`oGjd)uu&p&b$l2Z*BcN+H+AZu_Q2OV`BoAy@Q-gpJS@-+W@uJK-@F zF!U&jE&KpQd9u`5O9%BVKf{BpheP|#Mrz1<9R{KvTN`oX6p*$JSwH`Pf6zxn?)gFb zPkGQzIdn5yU)8oE?Y46jpMp*|-rBCLDRKPz%U8SHkM2y7|9VV2?>W#*=hlKi&kXF9 zlLd`jVQ3^Vk5muLcU<^mPx#6j0eFLOdIzB+w(M^+@}RMTcUQe&)2xdiR8k>Bzsu%! z^fAGgP3Pi1rFz}BXEo&1Q@uF-t)Ye?{UWb|j-IxHf?7zpOxJnsMe~el@w40|bMYVR zir?lHrXK`P*Sb)~V88Lc6L&Q@6_PWfBM$3CMjht76LEM_mMllPJS&RZ=AoDi$C3Z- zvz3)$BRXgmw5n}y1qBE5(DeWXasCr$Nbk4Q%??>jh~Kp8T0(P>`y4*UN_t%Wqz%E46b}u&sZUTqGt} zgZN)CMHLa{Go_s!FL#Fj-Qwq0mbTd!PIB_2rmjuI^LL!AS8{_RUHOj>$LbtV6|b;( zdKs^tVr43Pv$^)?sr~afW29M=B8^ZFGPf95oH|Fn=AKEHGgItTSd%fM$;mQlO84o3 z1bGjJ@sK^vE?hSO#Yl77L%XfF%;C{bt!j^AxWhioh5%8=6#f%8e5^u)q`7Evywszx zDBI{a{iLSzON9kyXMAl29W<=EgQ8R!>lhe2nF2#n6-*=4P1s}=_1vDUjNp;$D!H{~ zCHfDam*mYVAC)g1^_JSEbqXq5LB7Ot&u5~eqdRy_Kwl+ZCHgHnJ&4WpLT;+J$OYay!KU>5pri3UC+8fTBHv6# zei;r+0aE+ol)mS&33Lye1RR2n^G;_x)C^>ll|Dkh)JEcH>C%qaM^B_1(Zb}pQycw{K(n=?-?Y$_ zGBo&8yUH!UzY(zhD6rQ%3xnytxq(<@>+5#>0Hm@5sZ%dVvhWM7o~X;@C7htAufs8n z8bFYPQ8^v>1;w=^df}gjX0W_KuAr5LC=` z$;Q1TarL(!N@*+V1mHijO5v|ki-}-6OgF+VtMDe{g6iYb5$`fcIHM1Gy!pl`d1%RG z&5wJh`@p|ZEY|;ynQnaPL=aHXmOY*=byEZ4z{4ycv^DWKbZfxO!B4rRJ93vCxZ+% zqG-iT*|V#Y;g0T$EH`g5q{R1kA2IG3c;#?pC$9AGCN_ii`ynL0g1GtqNioM6J2`*tf53ZeZ%9fb=J?ofTf3UD+i-lk7Bwj;Q`h-$ z=QBYmsiF-0gPfL@RG;Lp2GxIQB=Q!?qGOt#$kS1h@AArJwBYAHob298g0Fm*QrG#% zPjBmxu8%*)3VrOFR{9Rm9|Q=7s@-_(S4{1sL||`moQ&+#t3uB`IQ6GLQj-uLP_zoT zuNl~7l|g;FGs$}N>%LzS&${OuV#l5vciD8iOvav|aPXU~IAPLV9pf#0?6>)~hZOl! z1~M{A{F;G3x#J?*{M1O@ic?bHHj>HG>4ZzlI9(w89nnn|DyIBYX|VEV|Gs!uF)wr?vFN%@Rh?>(JQaZ&*sgwlZ<@A%5N1<$KJ@gIRV-`2XVK!2&R%A`$8tC+X4D62KOR5?Wcb3 z=S>TxNH*5aCb4cNxutPkxiu`P%qdMehfz#M`fag}O@LMhkCKa)b%lPBh|O!p@PoGG ztcK#!8S24zMbwX{UdWbD*JlLiW$0-=C4W)8{OSBg$NO!$tD$G- z7=Xz3UvX+yzA2LW4c2&9cGFXXQyOyQ4h7HZi{LHi^_4;g&s;pt;$GPg=bI97oaP64 zhLwDkTbNRsdsB#nsS-JvTl*NqpE2ERay=_zelLQrvga+0NolX#tJA@&v!>D4Gxw;q z2I?2nX9gIxYQ{vqo|WOCGZFl$ey1uS_oY>A;oGeA!@pW@=(q{YJ2(YRFu4Ze4q?TCW>hpG>4%G9`yF%`4P$yX~JP_0z; zi@2RnQOB$06{U2jxO;#{}J%?!fJs>1e`FRa5SRsl)r50PH^z6rmhL-l}T|9Whp(P{92)L(ZOdnOXzb|WA~!xSa(9ASm@&Ss<-1# z!VeTfoeW-2d(f56TaU>#iXgspwkytu}Rh!hb>YI7I#Qp^PV_X~C!@e?U-%P?qraEmfx z){Y{b|9oXFFdp8Rul7g6PkO%a{W?@|^AE4xfNK9cmDVEV+yXg;^4YWauGC%Nvk7Ce z8nAU93Rc?NyMEL$uk9%>LXH=`1!k#0Q%9c1^AA600$(T=1|MnX6Qp|vpKSqaY- zShWVXx}JXDcZgdO6pQT0{%IIg%F(CReth;fcapP6rJ~w*^ISo5lb^Hj1Jmdq!$iVy z@y16*<81CdR|{l#&>S|bRvE9DuUPTMr)D{8kZyvC-clgY!nmu5D13p)n^Tr&dSAYd z^m8kRpiwKCY>IjBC+ZTi()AppQ+atLtOqP3RogXKb?ewh6m&)o5?4m;yT=nwr^@u| z?#~N;jkiWLpk`?9Xi58{y4`jf0gs!;1=1}ev~MC{R8~^}@!{A0H~4T?@W=fns24g% zmwSH}&kL=JXZpCiWKDUs@Z*Zu*@i9-c&dyNFK7{~iOPg}+_uhpyJ+1#7H{~=Lp-zL zRKs`vkg>1j!Y_qSYy4`mwZmk+={!;CV&xX8aSE6I`0-TeaU$|PSXMj&L(;q+$=44= zHK9x!EBOGwLeAo`ZMXyp-f7Hi&99b~87n{>3c&coNRQrnk|`k@MtvhC5wZ_s0dp=ewJnwaJTf?EmvK+Br)}?l z8gPZNV}K6P1a_NBBm!+|QjH*sRD|AtDgemIS4FwT)5v$}XCAE3;96Me>+LS~csOru zz9>8M*^bCio#KJ9m|-WiSf-eVhPPT~7Ms-Me6KoY!KG@f3}=O4S-r^%kL>pKJwjsa zYQKKH*Y@wzF0Siso%bC39V(i6@khq>8Lt-27gN&-PT4~=<2w4?=3`(JxT0&vVyf$e8}>r1(r`8I0I9~Br-4?_?hWBgvNi!HB31BS{aQj&v!Q~?>& zfRK?1M;Dw^j=Yf@8^E`S;jc8Z(=aw@CCM{4G^8^$Kc=7mv^GaP`WT(jm{(3>At6Pj z28oM)S>T1))~= zMIl3Lhmf)Oj>1rkJrgNJh5E; z-tBtScVycZ3C)jQJ+;(CZ~sf43*&T1XjJ}D=7JTP@QVauAnh6`;RgpDcc2*DdaKd9 zIj$2HMe+bi8#lyir`Lh+hhJ)1gMhKfruVHEj4Rf|tE9k?wo<@(#+Y#0gVSy=Tze~^ z8z_J(Yd+t7{<2^sc#Jh7X#@aypI%;mv9hR2R&otgW%E9%YjLfG6CVcoaWanq3+5Xj zJ+HjK51Ln4(rVbvodLyC@(Ia9B^HT>uIrKV&q8GDDl%nHqC6-LL9f8;r(=ia?9m*l z?vxaUpWy1w6WT2pX$R8Pd51xlZZlENO>BwfHa2xgC)-7&pLNrC=Yu9*fN#3LgRX&f z7r~qdCdE2aE&VQ18jXIy+TLLBJu7KvFc0$LpG42B_)o2ZQ;@FZO4qqdDK?8z6ptVOy{mz99(>P~@6a13T_@`{IXBNP)O8*?H^Q z)6pBkGV9nUnJpGE*?S;!Is!qpFdSl2GdME6Rz7Emhx14h@l>Cw#0k8qG6Y54Y?Q~v z575~t6NBirGJEZ}_0cWa+M&{hSZJyo!@;W`-OaY~qyN|lfBo?pXA)gEBJ-FbUnMXh zVMge`pC1nN9b?fDujI(ttypYtAes5Z8g~(xcK2uDemVj6!2VEg6rLxUd0*YH)*=G* zy#e1132FmH% z@QEoN-Fu_)U#SEZxf|eVBQGcoBgV%q+C`avgP;vu64h>WfH{jhG@3D6<>4`G9V!j3 zyk+2Hye{N9}QSk2eF7|2vUG+|8+WU4l#*3l{62Fu{mGLTU>=ugLPydxMA&cc#YDjBdd4JqNT8<$Z|Xmxux}TJAmMAtN&+4k z(S6aYIV)iJefcGHcVZ{=wj$OXS6FyB9g>G3C`JVg4iBu_S>*{-=h=YX*0vd`8`ANB zFVktHFEF*WIB+e##73bJv2gIfS59sXy3J?7{_Ivhp6=#cyQ|nb?(+bTHJ$o_rr85_ zJ!;DxB2Bv=XMw4D`8y)Vd)`SCobIHxfza>O0;8T-!3Zicylqd-9FzDG({qe&(tA{SydkSa?lWc^WqXB3F!uFsJC6)yEDPVTGj1D!UGRd>eaZ& z05>=;l(!Ylls8_Ri~wu(SL7OvBD&{?;UV)ULZXpU3ty#-2ia?}L5G2Bui5Bq43IzIO>Ud-$Q{#g)Kf|P_li@#7RNfR=oQYhwi3G!oN&M@85kMO zI3Gi~l}4QTDE?62xF(-PxU5MecybG4QyEeO%B#r)(R#q7hOcnXO zfTpVc6Aq>0Nrm@E3t&6}6-bZzlb}#LDb<6Vi)Ku3ZyU5Bd6WP}xdQu-(!8I*cUI0$ zTxN46FocwChtmcfn@<#g?G10wCO^G;4nu_nEg3XK-8TDhhRQWrVLM3ZoaC3{lD%e+KWbDRtN)$&djfZq;>?jje>^z zH{{WQWSe_J@A~@WVMr;Va^^zU2>t_uECHB?b5X3hc+j=~%4KC8^6k?^fQDkh-vjAe z@SDrLokr$wV#%`<&Ga`ni2?>ns{3)NBK?4gq<~7z-;s+$qzo6@@HWzU&~lmAd9p{F zAIB3|B746xY0+RqiytbIBr$#tqU~_mj*1Qbq46*Vs$xB`Vq<_o72$|TJMi;YpLH&h zp-R{>8If(QMR56bgD10DX%8vg`7PR#B;}w5?WaCsf=>8tcWgJKfb39+=$9}U=i79|G2d=7>YhtSsXZP8kPu0xp+I^~ zta2)DZB_L~o|@~4BV+f}=}EF6!@sfkI*;=|AJ2ZAeaFN(;NbEfM{=CeH%$*`aQG+C4g#VA|vGb2)#u&I78qpZaI_|?D?+4*@6C5{2 zXpykhRbIB<+$2?7w-(v07xc&rQw^NrK2UyztMS#73y%gy%SU6al}JjU?)@n)LAot0 zhf)4@ORVVX$cTV}#p_$fR9j?NFFZsEMLpew_Bj)%mF%TqC7^YAGWQYC5k2l)NS4J1 zW=<&ZG4)!XVc`8-&)fw*Ir}%>*|t~O_Q@m}6g)C3bxxt2T zecxhkF%Rj`lwAA024+>mUizV#m18C^eSS%Iu8Ib>iJV2hp7oqTevu!;sJ_ zK+|#Xrlzn4>i@}%B&W6!>5fvQ^thn2^!?w`o#|}`^6T* z(2Ns787Crmz(bnXxjDG@{nyq@3L+57w1T~R8rZXJpaxa*Kao5Zdu6>#fD>2?7DC9X z^Il#aw|1%Rg9uQ?w^F)(dX7KQTln~hh%<}RG|(eReQAX3jS^ZLu5Vks;m5U*z>Gj4 zBybV&U!W=vOYAtgE~kSn6ckh_lBHqx0fda>AEGSqaM&_;b$W3vIaj0FrtlhiqC@a@}&Ab{ZOVRUu_-%TvmDCBSRK3OOwZKbrPC1UM(V zhVX3<{vSt2vWOOE5#(_oaO7sCKbc zWIs28381iELlmf1Y; z9zAdLSMw_O_~L8=_4V>5^o3IXg;1#sa~9*I3^+tV|X9|S-^!UVle z#WNpnyrZ>&Ts9272?8}J(=m>`|B2+C=f<|H`WgTezZsnh5Cc|EPkt*WSs|BKROIdK zU7Sa$BQ&I1JN=eFeA#={t#+mdG=VR1(Bze{%#+(qlrTmIH*b$~$Uzi%0QhOC`4pQ+ zt?GJBV9G3`oSa+}P%$nHe{bHioAL(~Mam?|58Plczuo%*KOAAvnC1q=id4#i6w_GWlw?pWEklgLd_PaPKCGUPjq zxodp|v2!22+70U zMPTcAnLq&p?D7~AG{vsEi;|S|l62m(alV$X<0=QR0D}V|iTUJ^(95`a$Nt;LAmhb= z*hkLi*NkA{6dLVtZEZf$gsIkbqr@z8!*02?ECc>6Ft|B6arYJAkVk_7F@K>aC?(Q4 z*K;NjoYif+l!Xi%VqO$bnr`~|fMS^NMXWZ%#ygOc8-foAEl1MA2T+sW)L2O&H^hKa zIF>f6h7(ejYE_v$xbNM+;+l-X3iF|)WmGMX zdwE5(NA4!>ux)E?K6*(#LO!c^jiAQ-{1R@6)6kRG)C-M%w$Y0ZlgD0r)&-3lUARFy zs>E`sqkc<4?pzES$380a_;7i?fxjWqUD)Cnw3N79h{JR7#mTL3`dlLk&}%5d#67{b z3J@@>{F(Uo1?ooND8PvWGQysu&*Oc?nS^x-z+dYXQ4v8;02>#t{+r6bZPCB}4xa_8 zvfbc^Jey_zu@1^XUz{o#+YOp1<_Gx?h+x@3g|fX4^wJtjW8)`CS=bLByxP;q9*=x^})yd#E`!+>=;{!dY4so?dLbX z$TUzAdR;S6p5;_XgPL8H_#=D-fmPvZaF+eh4HFlJGoC?w;T8>0O5FBypQ|Oo6p0cr z8vvE(U3Iu<)4V&jLT`-wwP?P}uMcJFR|+uTbLIhEg3|W^Ow!2^6`RT`)MM-ccNXDi z@`8$9~$gNCuCBZkJpw7U#UGC&j*1>J8k1#Q85CIgzW#0qYT^2mKUS2#8WH$)c z`AuA%A`4^1D2{xv`FXMMU7_eXnGm45gwH~b2)`|oGBiTEVttaOs`(a0rCnbj-W^nc zs4Xp~V!P+R(z74Gu?@`bKpL+NX^qileS$eeXdx2}Kye=w!P&6oYu=NG&_MSlxP1WX zV@^EJ*C!jEyG1x}gWx5X@bw&CkVAIuqYJEda!x&=UwfomHx`Q_T@tRAEAOk^1+3n& zSoh=^-(_Q1x&qTE8aVMPp-fj3)PdZM(w7nMLC@^2tAUcq_#^?!Ma-{O|FP`bb21;} z9&mc?0i$>Stw|BjwUS`un}E-X8>J(-%NI`RA67#?ZV5~WPjO6%67E9ZN0~YmGfL)b>n7RiFfH>2ui9My2Kv9J) z#Am6RaaasoH1zS7Ks;LtMTK}iU708jiM$ZxFZkc(%jy0rVAp0r4PFA#2i=HSFzhUB z>%85@Ra;euIPvtiPbH)``Y+hkYrg5g(aQ*B)2-FNB9jCX% zyCgx`l2EzWz$aV+6L?)X)h7MI)pE*4fX%|Q1R0i^H_Jj6tqoWXJ?fI6L}n|=C>f5e z(A(4n{QC!JWWvB*(+BO@X~@ru;XRpku#B%8UG2gQlb@IC0rp+*@z7HyrGu_j+-~ z=u@M{>u1cuS?0|HJ|}?zZ;F2Ll{pzt*r?f1Dz|Oljgr?T!J=;(E@%hL9j6xIy_-rl zlA!#*b~_N~tf3in+w*ayJU+}&?)Eo=3gqy@-M%O1qYcorseTkiMa2c?b9vC6@gcZ*WMNlCQ z`Wr#(>tOnqGBk)YYzD$(;pzeI|MZNc{f2FDXbHNkkUnI{)$Gne!$HvcSrQc44)y^| zWQutFtD;*-uRiV><1xEJ@K;Hp0lImzxv+$sX zeeG`qCbRb^c|eGpM)(YQEwby|bHdA!M8jMC{4JlGT-)Z))s5RbGg z51DV8kV^*OLIgKKI}%xKfLBJ;$9Z8GZ@ZP`VPq+vz=RjL23tW;V>8kmeQu$DWNqW0 zgG8}rXYcmBKJn$Kaw8Uvu;X)oBj6-iLf7YN#%ExeefG_R-0zLB;0t-kF)>7d;k?;J z5%>o=e*3=Lg)J<%b<4IxcX>>^5L!Wv;MNq1lo1oTqpsXEDW$WvW`}ZpyhbPNARZT3S2|wB-2otstzJ=e0@f(RgsT=qz5T6q9~HDodZxM z7kgui{rejXyN->F;3v2m&fK9kgK|`)SD3=3+li;@Zl5CZIFfn0R1z=qwAU@ zlW+&|s^8qf#g$aRvRj*kHdhgoa%}BZTlgf!TwNaYXbM4e|GeyKg`(mRuubggdO&j` z(rHYoXOAI7qdo~_;q%Z=Ku*pyczi72KN@PZR5(>u&RkVqmpqfCP#6=GzH*Yp72e>`P|3Q4HG(S*RQ%kJQ+Yq`Y6bDcLYcU3}kZ14}2PcwL)m49sN7`WkKf1tUxTL^U-SHB#aFybO})bMN|xYc@Bd zE>&n=|Wkij*bLeCpOpsU)ifji~e~0_#!Hg@Jb<}p~H*CspY&!$sAIAru#U9!) z{Q!m8%nd#30(+S4l@NS}qNgyS0Ekh=|2)+Y&o5{A2>>$`SS-o{x36<f+aC7c zcLf#>5B+(t@)C6(Co%51o#eo=v6T;y!8t{)#Xw!+_thL#-S!C?0we*Xwt*s4z^HcD zMKh6YD+=Br$W~@*u(A})LBvWPFk9L|2h_FG2$@8wVS}DFnef@9W{zI@UA3Tol-a$7 z-PwHD_aD!C`zt1GWj1s~ao1a;bk`BEMk;LNvgL8f( zfMj-X83t}aUzzpdJ1lR<$CIvuLd|CE=cYx{}GW76DY-m4@wrM`1GvO)DTcHiV0LFNp7 zVz^EEr=e;Vz(pguw+b;^jf;IfStf(xvNYV<$8nm>{{78uyjP6dK^Bdym{nl3Lb^2Z zkb500#H1X20xBeLK-m3^?@gvV75@DusScD)q{U4)b3IMru{qr)w3+nd5g?+e0Myx( zjb1~Tz4UHooQsh5_rVjo0;zvGHzb22uXBMOnY8|fcvzs$xM6f;eQ5OGE3or-!#Efi z1YKba&e6|-6>^_6;Ps)x3qwFLD1^35#ev~hk(xfchjTwEMSjqSv>Zx+%lOaBy|tI3@QnQ?~xZhGeGzlDHml zOE!b#y!of#bDC{?n#6c3o__K9axqei8oQmWEgnYfEvl-GPr-<@K>&2yr=zTohe;;^ zNx>CbB7EvGXNFR5rq%)oX^w12<9091^b1DmGwT^HJB@-0 zu?>}EV-;iyulpUC{v%O9wSkV(BRPI6o#$;(YnB}`FCeyp%o6QhO?{r8FTV-6*@ayC zuax#$K7K%P@n~J%$&nT{bEra`A{~8;FNFxdR5|rk_WOH1=uT^Z3pS-M7eL=>%fTTy|B#`6T1E^WF>2BO1v9zWy1#F)g^4-hsp(P4J`<-dEvjSkzBUcoiD zqj_}#P_4gOAmM+?4Vy(NG4VbrQtz>qcx1!OLDyHTk4;BarCNbccOTZC<3%?>cca+7 zRF>^W%}>8Pcnd)qij^Z#x^Jf^{YX{v;B)GP)5{H1K|eQp8qk2y7juq!#~^qP99R5- zmC2TsQ9s!_46&N$qErqhllng~>BOslsUR}H zS_L)$R64hvq3+g&)|Yap7K}FQd42WBGhX(MEc2`Wg-d#1=N(I^3$-6rk;gO;if7=~ zbLmdzvB5cZFgp0jb?FHNnZZoXen>lL+O3^VZVS{0rIMhe7cg%*a#+YdsTk0l1GcQT zU!>x)C(I{bmk@H6)fVOJa`eM&t}8GIr3Oj#t)RJO`8*&Ge9AK+6APYVwHJk6GST9J z8HdXj+$V*!jE((=dEW9-rV<3f6U#?$arm8|L1?NMdkbEG?ZAbr zK_S;^EyQrlg2o=5;HBG{SPi{KMN+=fd7uJU$p{CKq!yCW%Rtk*S$KgL^$lsw386^r zZ4GVz&v=lIgPgXIQ{dCzAQFGhr`GgY{={7E?)^CWcn{@_A(0hO|3=(JX7cXS6D_{F zy!`VmI>)Gp>piNAp+E=WZA5X)apxuQ%P>WgWmsu*meB1(^Od)Qvtpe77v#tT>EI7` zyiquxq|Iav`uD0-0u((9n7@*Xu;aKOak1%}9tUlAG2r8LXWq+H?Th8MnPcuKwKD{( zu=rn}&N4qRg`RIdDj>#B!f3X{OaO8P!05HC_sNNs@P;LM+=(LA>)o(Bx+Ho%<6u77 zAmle+T8&rTl?V+br9L5K4sdzZ2Py9E>Xw?gj_b*Zq$vuVUH3A#C8#^E78Id+Ip?72 zt+0=wHtw1BJ_5tQ@}W}chZh*zle}vh`kEHVek#2#fbA04=eNQ5oR1XB&~vV*xeBu; z`@n(#a!&019`5_PuWMavt!rUiGdO6f0gBJ|+~*07JIaa}kcx7w7UpITJGfVP z74KQQtx$~NlDs~~^C=YKk$QDh0-Aqp4`Za{EK-GQLE%e|qJ*l8(jBzf{hEIX&BJ;({Fh|slQ zm7I5sSzC=&UlQgxfxKH2r>qWh9RYa5czCtITEySSC1(!18`Pr9cmf0URCM|PP)EvK zV_@O=?%D&}kR)&oj9>IQ?Yqfuu}^}zkZF6E?=nm-HUGgR+rDGYDp;;aqpN?L-{MQC zw;P)pyE0n6+&>>49Pt+2Vic%SxH{(bDmE`7^U?7a(HIATNuE6|rX`_n>!Ugc|vcY5H z_W}P>T+eg2Sb=4nq2oGOm0+Dmt@}xL{$Ufaydm&n$0l8Hu13CFW150KnlXh-My>Y_ zzlGYsNqeg_0}bCpK6Xr3r?8S6KJjIKmsZ~;bQ25upmX3gmz}z}M-Gex*=cKiXBsY< zT~?g8X|P(Jf>B$GWH=sK!-GuvC=yW|W(|ArTYTe>t7N`v*^u@WzQNVQ%b5z*wg<6j z6SsfJfnM(6-YUxk^qPB^_78P)sO%exFQZDtVpGcrW&(ytn}(EIZNFV7x>ElW94_nN zj#?P%#uScA4$;+qP08IW$~Im_Ir*X_g?$7|wfnxI-?eZ0L%ogWF#L32W+AK)P*3@< z6?d*wkeoP^@yUaMXtTl9|CktBJJLh!JdEQYXr|MrXx^b*OksJ(j6wIFJg5*XFkSRb znQQc|jypS4x)IQxBMjG}D&f(~KChPPWUEd}#TFnA+RK@dEMH;E_0e?#-NqF3-AaA? zh~$0sb`HXNCaA~EeU!)0G@T5Cg6xrUKO zvdQrb6p`I<&VL3Mwp|B?Io_gC>qX9)ELAPNfFS`fUXO=Am=i2KqScZL|7U}QasR2#wa^n2xSj#fd1xK#VenJCJ3|VS4{zl-_p{%^Rvjm!ci!G2dUJ^ zfZ&bBvOREVgQJbKX5u7e`qvF@~woxOu!qvvLIKeClyDqYWTw-ykWOH#oZ2k)f@=0@WOw(wQ z#ErPi24{B$4p(wSYog$8Fy@XQ-P*TKF!f2gkznzOt_KlaALUQ|EmiO6v?G ztF+0;82LkpT>fsHl&vf_CgF#vk*`!CbvM%3cq2CdHy2?4AzlxnF7)7I`H}NH z&jm?+63FhfJu1T#sRw}`-t^g>7k+7l>^s-6QJ8n6^3jedly15eEm`Q5M7_vnu`->1 zN>kn^0b&Vb7_Fv$Mai}D2LFMYHzsUqKKGK}D9Rfs@M?0EQd&+FB7fuc#JX#eO9VP*U6O@hp2#4NeS z^L{i>Kkp$K3Py!gZ}ke4tkiz8uiPv!_PCA0{Es$TYI)So{Er&BUDoh2HucIp8{EJw zGOUTAAB|o<;ekSx6+12SSSY6JI>Dh_ESi&sE{easYW;|ky=lFF0x@_ty-#1>KB@B( zi|G8meu|@dzi;x?&M^OM>7Qfg&03YFBKw#FxvO_hWX+#BD4*k?H0+Z9w>HB?sY((- z+i(b1SGkyg2FUTg+e ztjOF44oT|zYE|^fCa=s1?*@kCg+k;CM&UiggA8K1Lt?1%vcK^_eCsBI+Fa5V$~OwB z(4Ds~pGr}RGfM-F_CVkb8HV#IpVS$CX5Otnd4kM-d@u+DTrLl$k=+mWSx{wenR*&9 zuLH-dzaoBLSg8k>gOTy6Rx0Pp@0=9vEuRj2o$Xf;In_ok!l(X)@7?6l0O5PgAC}%4 zIr(8}zL~@!cI%Gz&H+s%Tk`hulf0T6R1$AEEz37kh~0l_p~T8!;~h*Py0O5YgZh*! z&U*+YGepstIM>K`bv;;|&-JBOk~N~ZEP02fzRwp9Z^s^jYDMNQktI&nhJ`NSfzkxf z$6vg`t3q|hAShVLkcSBb=j+s#054OjJnO`3T+TN#g{^zJRz-Wqa^35c04u*u>=45!@@R(Pvr}#By{h`&lbHpX9mt=mweCOS zN~33?&?ItMm^{5(V+HkC*oJ0;5(0l`ZBL!Lj!^oaTt(Yo=PEt+NP|$%O0K!bCXebY zq}d(Q$@*fEAlb7@;}U7ZV`i@^nwL<0hy~n`1GA%Ze4;ynG1i7?v$(b%AJm`F#ev`0 zhs^E+DRj`v)V2?0-WM?;1VJ+QnK%ha-3qbBNO^W{ofpZmmmeS9jre~?^d-&rH#fq*Yuc-Xx-xfH~--kf0v;4!9 zano&uy>Is{3NMb#jPx!3<+in^kNf-+(G7_^8r0KlKKt_rE{FyDwJg!Pmb$@&r0BVt zEMH~bLH6=(6A|3mQhd#{>Cj8HV)@HvFSbpIW&w8%6l(EtcrVB100iIa!aMVqT(yUs zm&&*j2)3nCTl0XfnLrMKrWN-X#Y=q!jMvEV9@WJ|7qpfRC=;?hE5A26JBs4EIyD2u z$}>M;)3%Cz2{ccz4ch2c@obG(RaP`5ic&)%vQ5iJ_tli@rzR@S2l(A1>oYJ4b#;w3 zn1&qbR~oy%T{f;YQ+{z(VhGw8dLb=#1Zv~`?s4GyiiX(0HXpG4t?M_3Lv%$9iXScl ztG%_2yr;Am4$J)|$#3W&9(hd)--)6;NZiH2h%fL!;v>ln)g=xv0F3FCa%(e5P;7RY z!I@3wp+Skn65HMQQUt$pt;YL(M@+Lxp)IQ?QCm zrH$67M|>o+6wYG|v?(@kb0F1wLu$)>w-5~=Tk=90?uxN124^Q@qCz@ZYx%Bb$~9>|!ANVXGN`Z&|yCP&Nl z;4|!AYNPp!UJ;AOCY`*<)4=!8e|pTrW|6Nh*4 zN3St^8pkrfOQ2nl6gAjA@ZhI4eN5Nd8iDVD6sITZRgaL)M|xf|8~pu1oy$rSkjc}ZlSSn#AH+K18Wo?YDS^qPlHmULCI!AeA937c1P#k`aSFJxA$PNLP@@(yve+dfq8 z8ICJ8p%ya$HvHNal_fVCEF40Qw0wT!0o9QM?GrcDj_J_($6?0^MRMOCJbD$k}@#k=gWhA&SZ+;+Ku>ZB` z%fdfM$$$Rjeurk#;K&3in2d+-i}PE?!&tYk|tS%=0GlmsdK&D;QGY8;5C=j8m8-)|cqFI_jKYZ!9np{$uw!0#k?hyGdxluJ9Au96Kji+XSF!U!VogOTY zV*(RHQfc0prWj!y(YvQ^0h;97O5|($@}V1e)5amUIj^@gMMJI6lcvRtzLxUHm*Pij z4lbR24O#G{AUR@CkCwfgV~RhHKyB?$(1awPNps;9c2`Xfz07ork;nV(>9lT9( z9V>tF(KiCYj?%9$vwKzjY64fd!ON~b^SybvP?S$0hqt9}KUJDIG|H~M36 zfW&mMYO9sqaGPL-B)6?!S=%$p!dUurcX_wa@a5gWiyw*z7d<5K!Nr`2nDf_dO#LrK z)1MB<2*b!uG6D-MviRH+`{&!GAf zW&jaE1X9R#Oy5&3@lq~@8411sd7REdQz}A6!whF>3hqm!c$ZoD9TvHmhuEZ6wzu6x zMEDuI^wt(knNPac$YOpoU(dWgUhm_lno*^lek;Cd+m%&bg9+P&JvTEa!}i$njq!sb z0}bBqKe^UMQ(hq{Fo*cT`OV>#8Yebuu&IStgShuVBFe0TRCV_H)JA#Ug!19;w7Xwm)F zCHtB845nX`VPMQ>*`d6doO`^rJW@}WTEl)X?`&W`1EcUE^QAKEOUFw0qfeDpjs6tR zF4I(VZanz`UX;cS+@d zVDXliTk(Ny2FyI-U+<_WFR7Rkh#5Up92z0GYyzmm2|}V=a}F3_JU(ZGwdD74Rn5K> z^&{G>Ds<;T7U+2TbC92unWI?V@D0gh-ahX3^^tw*W8EG1)VI`S#A3C-SZ)zryvlyE z(S8xq9;p(78Ilyb{_(#sL*~;eFLn|;*Tn!N)DNa_qzI7}A{ezOk9o$r=e{z7qGC=t z9`h`U>p&BFjr$MBU5s{kIUL9$GP?8r`)*5|xq=JH)^yL6j@B$o^*A)!AGeZy5enG| zXYuDz^*z<@nv5_gka)z4u#RCLRD zBr_KgW|*X=rX+I{u8J=xd!dB2aWx4KD zwSet3G4JVo3FR5OCBAz?Q`|i3(aNnyAF6zx1V6?t_+V&~Rhd0FiR+uC`CJnQeOR>I zVcuQ`rkD2MCi4EjvvdH`HF?GkBppZb{^?qn6i*&Cu$4X~<|E`9L{ltVth~RqME3>-=D^C#2MX!$QvwsXSNV(Lr{F|IVf0jL{{?*p=3sj5^DJiW z+K2k;B^iSdty5*WRT;K1#wtZpl%3^$a#hy~#YgHtYEn;(>7+<|>-spbsWH2xTvZ9s zt4Y+erYL=GW)k^@_n{rYAV@MooBiSOPPz5#*}SS;ZcDmNhSgM@d`@@|u=t;g2M|z= zP|fsun>|+CjV#Y|pwZaRA50FUcyGVhouZE|s;U-1pBOV{0UmC7X7A6h?_HVA&c;oO z#S>+c^ikfxh*yahxyqvHy(L`67|Z7#^PCYEg_xAL`vK8!W}NbWKqHROppd$%_$(8b z>h>?TusK)!(Vx_Il^7&5;FL%0up3|cU1HJL5|S+0Q#B}QRM@iYD?&2)t-vqce97Gc z1{#eOfMpFx^h|X1$CKNX_H2v!eu{cA2tA>QraJH#(l2%s>H5}#pE#o0!~~;))W9gY zM0lEHA1JSXQzW)s*+9e6Mg!7Wy=IJ%I7YFdw(Z!X_gT=@nivybru70!obv(FNZcPW zk@XI&Hp$kqk2a%sFrVD3iV#TgwxNDMGh)qs`1B!tEFHefaq`R{OpO<5Z+sn`1fc_~ z#{?XtRD4e~FJnTRcGnDml8vrc;c&mfnZGZFKc^Lfkr#1HSziOxbruZ$KHbLOynXes~t_&zE&PGf2=e`We47K6}nry!Ob8ePE-0H$IlXWK^Bif)?A$P}6; zLx&5JcUyo*Yq3}UmhP_ur=hrbN;GrcJFa8%LSI=i9%a-1#A9qi=X(jQz@=pp-^2{i z&y8IE$W4XRwEn`#%Lz3Y?ws!z|2%wabQ3ZjIF}$asBNj-p%OW=ck%NbK~r>(M6dir z51|fik{*zncNfo(sABrATBh-`R-f0#PawE6n!dtx-CJ`YAHw8&^2m`GV1|k$3ba~Y9k6I^S zB%8A?N?%61$95@V@-xV2HfJ5lTo8RLie+OAmq(4N=T8_ADDFBl6_%78c60$~qwjzA z$n3=^YvXX1172daD73VQvg*oVZpK*7I2QY{RKpwM)$}YpCIk{fG+=mx#XzO=Hnfvw z6QZuU%rd+~swd?-hHc0VT2!fas8=Zqlt;~qVXYicX*%em@cbTg#fQ^W?G*O zFMpMEMY5)dfd;9TY`ZB*zREFKY8SEni;D!_bk~aPw5K7&)LCF-CU9BkV|J&`&7?VT zK$gdyP(>ma_;O(@1LM?|>W77sR&@Cbg_pIrj}L_06;kaFJ^aQ@@K|w*D#jfPw?Cpp z(Azo7yW5gpX9;00oC>F)8ZQo}caPR2x>az&vby4DABan*$D!~wrzw-OP7J}u`yGkrF~Nu;+i9E06} z`~&h7U=3_S24Ep}W54y-Iw89+vK87+`YKM^8)^q=x^}T`)tTPpMpD4T7E(o+{6$Tno|_U&&`=S^;yjf+8p;z$D_F8-aS^Y+pz7j z!GZ&!kY*%fWY>rlH^5PZuu|RzqOICE`e5kM-^^ZpA+ zvvlnwFaz$lZAGPxo@T@D;LyGb7y6qhwj`|uwoGKun1b6E0JT!>l2?-3VTwe^D!IK{SGi9&28EFDPsPa zu<#m+se~hxEr8Q%13$>Gh7$1}#hdD;he{Dd^(Xh2`PCjP@+@ak+G3EnH)B#x;m&i% zKHcF7d(aSKtd4wE_tcL$8oFIEXdDD&Biw6{g<|mdzi=nrFSCBvtAr67Q^liInkCD> zFY~|4r&G_GIdEtSAWSXDRh1C=T)%YGV<-E*&F~r@5sCF&a8xx`Ya8+0}qKu=v+r>aNKJ&&~TMt zQc`1x;yV0E9!$InP(NEPhy{Dcedf7K-ol!W)|h1P3-p3h;lFiiC}5fMI)mD)c84ZT z(${dC#4q7Wrat&BE|@;%c959z%1eXjV=*F|ErgE#O96izC7#QqGX;7FqD#0b`qo~? zXv%$x--DYhzP6bEvG{f}rfL+ycT2t&Uc+>#+ROQ6piskfV;9TY zQBUoZw)KTQ@jo&#{dvz?W136g)a+af-qB8^|d#?Kl36682*!q2A9yl$;m zRZA&x6#E_y*r6&Yx=B796HTMW6hLdcs{^IihMgBx~!{*6wXJ6>m18GXDOu!hsd?f$FssZg9oCVE6{9}ozT zcD-rw*}@?}*X_fasHxykN*2Zz3r1QG zpqZt68%#>WpBV44ZD=S&$g9s2X7wt7#PZO7?*z(YUWU zOKu*Z7!iTrDi}JnHYoKtQ1%ZVbc&N}`860A4-~qvO^@QTy`g?hdiaS8 z5e)l=Fu(Zz$seT;j6+PJNjO3_9l?UN>8kr16uV4+duU#hBTp^&nOI zPS*G!s(B{$9nHzi$ z4l3nQA6zI{A^rnj)IYI06AVT%D55qxPiSb%_192#C*~Ob5L)(qj2GPQaf!~U)jqH8 zf17sV`CrLM#8B@zlx_)q(7_*0<}!HRptQ8-41g*%6sTf=P2`wmm>CK1Q;uO&b(gX{ zSwAKBpiiT!cv&ocY+}sDi(F4=g?LYwpPg_tm2BH|Rs76vF2H?5?fZ%hdn;dqgVrk@ zt?3jgV-HHsnVe*&9bn(YB&_zu@p}&A7UZgS|I$K=9tSFpTDY_)li~3QA0!mDSU=w~ zX|%vyba$5>HQCSrqHbH4ZqtiJgKlU@1ySNDrn{OUB<~?8I~!%ZH4qsejYV=PMd?4R z*|RQ7Yf_%URh4%TC*B@jzX5AX2&H+Mwv;C93bb-AWc4X!Nm6RVsj(~)#5mu`Pwg;! zI0e4bZeBCh3UPBr=g?Boc8&_M=*VG((%l;4xRq{n|A$^BGSCoT zK>Ab@uhlNL4+4(fhdHPg8#W%;$&px^LGzZ7c{H!0iCy`vOE+a{-^n#e6xrAvzhe8= zPRf_oj8CqtV!h>aWlPw*qOp+hqlcU&{~i-Rem8~yIMUlP`OV^yD@6nLF43LA;m(z% z)$aWQO{F4DqNbL4tZDP_Q7)R5Y>9Um_;!5QK8vPYw_>XsEbXXB1YSr*2=`H8Z6K@| zKKeX2Qk0SO*dqlY`UINm=k=Vyj*J6eK4xjvKE-IN-jl-BwJ~ifXF{7Yz1vpUwU=1d zhspB_u-}$x@qH)DrZy4t0uL{{vum#^sa&=s-05LVeQZ+}(SI#gM{! zeGh9aXLOrtru?rn*@bbUHMv7jNxujSoBDME=Ov-jvMM>!_m(JS$Ifq8{U$iLQ%pR6 zAh6AC&(0@~@67|RRGz*TcuD0WJQ(9Op5_(*7+dt@fR2{Ec2maVa{``*RBD1AO9g5;?)B%o%X@AHVK z{d$g7nz@pUu{jlGk#|L7Om8nB8K}o=2AI{>hbe@z7W-DrAf<yjYvX=S|4&%BqF@0YrLzVE1uE%dYI zQ9R)ZEWD2-my)K$z{4C3L@;8ffAn_?!nuH_{-=UAm~9VThw6^IRM6y8S9i$vU1Fg{ z(!RaQlu$2;50o9~&{c3(%DVkB#Fr(>?09TFm^wQAV%(NcW|fG>N0P3N1)Jb<^GFZ{>#J>pRSpd>a$*;p`wp(iay8nI70FSZv_L&Ut#^-080)sBoF$j$_HCIWq z32F<#qNuZ3)}AIuKXSz&)24AhJl5r{-p^W*`kHAho_&- zaiS;^)a3iu$?!%uF1oQfz@*Os9(<=urEX=`K-Qm5KYz6)Md~{SE=6W^WwFEnDSk!j z%d^zn_eAC(5LE+>!N;CT6p2TirfKq3OeOpJiN2u?jH1#9BmwhmMpz|iiCXte8_UmO}-u?OwZfJLJxN_lZfO?>Gl5pdh+Z_@M zg52f_sDbmk!DfY3G<(^EILLqdb2vtHNn*04+CJJ7vGtLlKnS97_nAeT6f3(t?uNe4 zb>z@p6-*gj&VB0Wp*4;lor5P4dBWHU*&stt%A2d|Z6rH0Hnn~xI0_Arsd9>(8lU)* z?6*(4MzDJM7KmJG43hSv(19n`nuT&N>hQ`RiN<>vW9N@taUN`@Y#c+Qbv?D&-0@ihey%CV%pkEPLjqgtbPQcfP5P-cq7uekkEF! zHLGKaJ$dx8+ZJ2j6G3D%1)-r5mG{bd-+!sCi(DFkj@+ zWRyQS3=#{Un|K*yWvi}L^HC+nV5qMUR#hQ+5v)%b65MU^M_8)5Rv2kxNDVVa1+3%Q z4BzPYiZ%zNz6`Q2_m{bGQNh<`0lq?IcukKw(wye(SI2Ze_2dGtBZ?oG= zQ)dGWox=<-n4e!D_$y+ON8g6Sh-4Hp#8Z*)Ht23*WFJb+OA}Y}(Mw5p&rZEUv0zHQ zWUN0YuoOt;G8ksTe=Tx3JFgv$s32q4Vv`Fh0fK``cAEVtB8s!6h`f6hIvp9tpUK^WB^ANJTrbTg$^CW@Oetq#&TTIaUFgzBewu_kuuAwG zmsD~zmBI3Q^f`ekkdf1=7}mS?jhek};Ce=uXM=v~Tbd59J68aSMsUl@%LWy$Ms;@B z>_Wj|XP-0voZ4G;h(!OAQh!Fj;#ZIdHE>zvG=qNgb5xWC7qS~*4LTQ5{y*f>&EfbU zHJ<=v33o5k|8RUyfW=iCQ?$}qj+q|!cQ^s5ls^NH`3g0)dT{BCKpH<2E~TUAla^f8 zU8$m&0u@{aNqKUAM%+L^fISLJJ!1B|B|wECKm$ROT889WCBuDCru3w>`n^BO`aohB zQk_WejNO&}ACh)}xMaF3s3!ToqMpjd6WL9YNn^iui+`gFaY7;k&)x{QQPqeqXv_$? zQZq2_oSNxUJ<)Y9N0Ii*s-cKvePuF3GM(aZn4_+{J}*UKCtY{*Tks+*V35kUT$`%D zKjYgYAGr-=Oe{iMJ)<;!^1;p0+a6u?A3N8ouxYnwQvwDNPE#9gbBZV^0m-RQ@ZZX|=We?qY)u*AM4I^X$g@iiCWRhwryE ziYzm8ry<1w178sv9n+rJW!|gWTDkAuSQ&?%LvheT&9_d7gps1A=bZY>2>XowCBpi_ zb;h~pZmuc|J_UJR0|}YS*QQh_^FS3cRm-3|cSh=VO2ya7#q2sEO}!d|1@W!U?$p0R z3|h3HXm9Fj%F5`{66 zyKo6v6~>dfQ>;!P)m!FWUfkPEUUCL%-W@{Sd4$B^>K)>!LSxD5@k=K&!mT=XVeGrN zlf2eVnS8Xddeauz?q3M4igsyG#=pU1o0s3;dzJz>ES+8jf{sND<-GMNAzfzX9$Sv- zBR?5JvW|_N_&U$z52Vs^P>S4y;W2%O4zLL+tfSAr%HWPhf(AhkGCVG$LH3$9ZuqcV z1J0dQkecdfP9@B{ux}5^p1foTlHVhO!5{}@ERRz+kXTpvo^AT0|3?ZpvQ9B*hq%E| zmK%#$HTyzFLN9ty=?j!s-%X|YlVG}6(nwB@JSLbbuAc$&C4*j-e_2YI;TJX<)K?}h z=*spWCA4Kh6O0PISRfZC(RFh-p*s)AuNwAajvYw6oBZ%OCTCU+2?E%)R$r`^GvN9m zCt!z4p{G6ouX<|YYr@EN9?dm^hyEjEhvUBy(U0&EI{S=PKe6CEw9pB2vm<Pr|?pCq`cfU!sSiV#{1<5mbTytSjWi3LOl95f#;AG}(w7=_S5dC8}jz3-I>aoWL5 zka=f-c@ndC2~ZaI&8%2NUv|z*g*p2_M!{>_!aP+7Nw)BFI8Jjz9NN;jdG_X|f*BYQ z5kN*p0528AMW@s{Sjkwa~SHPEQ{T|N0 z`Cm6HHw|zmDmqbV$Ie5y;sCOM(O0|R-%`&9ggAfk9)&p)k2UUSC29f*ZJfvk0WF*B z>5&DwzFSjrv4xDe)#B*P!hDy6y7Y=ltU5B`1+TXP1%1@Lk-4Uzp;@BY^t5Ya%9((5 zVi%%O+{EOn2U#s2?MFx>?%%k!bQ;=f(L%*^UUL1RInHDM`TUJE^pP_XTuH|!unoFl ztX1+|P~^8~&$F#zp63aus}Tx;-q7E^_|r(}NN6sid>kHfuQ1^RkkR7J{b@g^DXr>{ zL6oLH8xz~C$%9H8>L8E2&$VZIH)s$Zz=ecoKct|$CS2kIh3w$;^Mo*3ig{6aI*~pP z?%|SZ`Qg(JQSKa@u?rT7^LYL1^sLL9_#sUNVfVJ!8T5XM&Vr}?n%A@Eh7>JH*STX0 zl&hQuwRC}YJN|l`?gcAqGtVUvkaS}iR84Ux;;z}-H!P;$^f&)g$2H~MYno9Uhjfs4lHVoiwr-uSHz0~jK zzba7olalXKFkqtB9L@(vW+LR9b@R!oPHhj2>GDr6lg#?lvnfc=MaF22Zm7fKV2Jq< zKDL$|F8V(6XR`a;3DF-oA8{zHo&Z_>j{$v+Io%Pll2NO&j0B!^Mql?r_1&nfK!6>?2!1`z&W{%3ZN|m z{?`rGm@LwG^e)fh-(A-N4Sgt%sx!~oW3T)3YNzpYWw{|zMxNVE_E=_7UrVmiuOenV z5kb@j#wK2m3-AX1`SPTet{j0=a~#2|E&$K5?2=*h^zSbw#Mj~Lwh8}s`oYdNm_PN7 ziYN38no^NGaU0RuH6g304^X5UT|usDC~%LVN$Gr>eTmm%Nb zTiHt}!&vVb8Y#`WNTYkX1fjU<6Ha1d!k{Z5ylm&pcO2mkD>Fm+Ef=70tn{g{auF7jCR8o5e7EsU+hS*C$w~CRCE`M$_GVfZRFs(_*MK*gZRJvv{H_6 zumcb#=%@}`nrATK5PR9{|8eFd;G867@>{?hmw@1YNa`Q@ZTf~sE5%5H3#t{|<^}uJ zckPLq9gRRk!fc+C1fYlrREwp1e@9rvv3oC;6M}w~;7~C~D^?G(U@f7f@2n4=$sDA@ z2$}NYzk=SMq~@=mIA78Z^)*|oYukEe#DaaH3E+5T_tM{9EiHQbgyRN|22He#;@}zi zpO=dshAAk!XT{+MoJzp_Y(om_vx|h&9rCjpbPpxW;d_I2$o2!%lmJr!5t0F_m1d@P zUAVLH(Q4uL73}|vDhJtYZzw>o|=|NJ1#DT+M5hLqN z;0WHye}2S<9W-#QkzpwE+kUaPES(9H(=Y65ST4L>noTd@N9q)mezvE+Y8{-X&bTxuo8Bfoqi{f9QhjZ9KxE<_ z(C`;EpJxpTcM}qaB)i~$O%e*8{VIH77y7#BOSr-9PXd!YTVNwxpqRu4;r38RJi@ss_tuzS2{_VMh{YP7rKrtT2t|1b^yXXR$oXtNwv+$%iFH525Ck#5R z4x|!bugVPF+JM{AX^k|0B- zt#IfS|ICfbt|O-C6czfd1!wHsI#I_zS(^WTcTlD42!m1qvX!lNN#WCRISomo=a~4#;!Vt?lYHyA89khgIpU1N=FDEAW2Z7F{`WH5NosF8}?^?+W9; z2AG2?VR$M;E!9;X;WOA#u`N)?)^hfl(rx@?DQDa4I$WpY*yy=pZbCpycW0+w6A@o# z2_>I@r%k(Mal!n92u<7Lby zYz%%sDn1*)>Ghb-+k;X+71+kAt+W3${rxC|p-NT^*+*Cn{^b+vMU#JJSt?%YnGKnuSm6)sTY2Vw&g{)hzhUCPI1@<3M2~S0vI(bSa7#m9&3#rjZ@1j5 z#Z-d*Y(gv6^9}z&36`&LhdE3wj;oyoXMwzffX_~nG8;E+k zLIjO}R6r$Xg=Q^%E%rvT&bd`Pe<^|~h|I^T08IC1Fm-GT`yik?^DA}<7lmxNRU)qw z6v@T{5I%U(;T9eCVw$07srknY!&Sdl{_8DW>J4u8gj3r?nv1PW?G{)Xoi)d=AKpS5BAR`)$|xRG zg((G&Qe8&p2!@$Uf5wNiw98BTckw*?NB{R3UKMi(*RhW1U=dl+SWP0S_e%0A`P)XA?CEUf0GJ4uT67q&c%(JWf z;E7Lw6_SXgYp@(NNCKOB+_351jFN(LH;&Iut#4)ztG}$%NH9l5Sr)y&J23pHZ&v z1g8uK3cE;jInb<-N6H4K<)_}3-md1Kylz% zqhljKyUysAkAO1ObL$x2u8Aa6LDg^_xjy%Oa9;hL_+=*&tr?;p8u$Axd((`KZ$xXR z9unXl%-i-oc|&{6^d@kBgD~eCyhZ)r&&;D?v;LjwyNVx*)$pZ#@<>~={?csXzk)=} zbF9&Ee3+5)+a~>L>f1T-juV?0Jd1{<93r0*0#MDRhJW1knq$>XbNdyucPPtS29FxT zy?;CpG;-^%nncH`=~+X_$yT9WZo3>+!1k}(SdI>(;&Rbt`C7sOY7(5R_O4R@JUe=9 z`J1b`NEf=K2{7|H&hcsm(XV%|2bVmZ^A0u#Mdm*E4BP`fPoRxI!t(*^P*)q%h?XnMv0F7G-|_&#Q*+;I7p6!s1If4;G~L z@Y85q8%=f{ zD@vhVvT3Nw(*)7n&BH2t3|g z)R+6YB&#pDFStKrfk5VPwu|2@7;&yfi_sUatw2RlJYdS_84V3B-EvN;i}U8w2yUkW zals5eIB+^rCfNu@y_M>Z4W-fr1vY84D_`Znk z$)Q&hC=d>#_@*!&-uCAs&mIYb`sBEVhDP!isCPDaEnTa5k1j5NxIDVbv|KRE6zg2G z0Q#b|psZP6GjIC4!}j9p)S@Ca{&q>ze>Q#l?)Gw=J+i`%y$u#>IQ(uP$~`m`*t2%} ztCd`6y%<-o#AH5S*ebk2xoTdT7kBxuzm{4;|Kv*z1PQxfPPwMzvla5y>zIdD`RS_k zD&pSUUu+}n*o>CR7YBgtSct{eweB)A@o!SP46Oo4w~^8Pe15Yx>3FsiU{ZH8z!wK=>4IANatb21M7d zj@2GBcd%U@@13*@u8)r#I{GY~zaK=*d)E^?pLnRtMefmV&JQ`}n6LeNq5S8C3UczJ z0Y8FXc+wlws9LPA%G~YJD`#$<8?gN6G*}a!1cq_b;R-Q}qwy8h?$28#FDKqP4^TAZ zlH~w3?f1ar&_yy9uD9f?kqpz+sCy6 zdVfCkZ2@$&Mt{%8!^7j~p%1~ckKvd;N{=7NlMdsFodmuIFpXjE zl2Mh`2c^Gm!D;0VAT3zFTV9;$xV5DKMt^B5Z|>PLy^Uz?XfW&LDi(^2fq}t_cZ70C z{9+5T#YHmHujQwL)NYHW#@(y7&iwv=d913spAZ#qfE2Q`YouV6VgX(n*ZPCYW^V42 z9t{8)Z`2*9mIXQib$kp^^DS{y)OThvPTKb6_RK}Fx^>wLm=PuV+pfj zc=Avm+mWNgeN}onoXba`pm~gabC&&e=k$iQCN^|WynyXLKhdwW*nevP3clSNQK0d5 zZ$N)V;PkV+!z7zQZUmTOi z5l>4=n;79^3vBK+2I@V=r`=p9b^9H3v4&_(QfD5#yB#g$(KTs!XNLHisASMgx3ywK z?&rfZZ(S2_UAI}{_O^e#QdI?gWOc}e9E~2rRfHXlNQJL7CNsg8t^n#wR-9GuHluaI z0rkQ)0zzY)^H8fe0a!<}?KYC-5VhO9v|OMGV>L}cRep8J^vLu_bzaPcF+K}gd8KOg@ciixUm2tA*m(8_{N0U~ol%*7 z`cm0M5FHjXnf%+P|8v#uTyz#qnWC6huom3|U)0_F$FBC^W0^O0%!Es`oLrPVa2jiR zvr-Q_`XJsk{AS&~?}Tcvewn`KpU*Dw$b}4M-3^H`lkVo6sXHHF+_4_P$`^G@sOO2* zx2C^0Sc{mF<%eeb*798e1K*zyNTsTl^F39GloL(eY9TcJd7mWdWW6SqIlY*UmUG_b zpKtql0@LXi{DA)NHKvn44h!Ri^Y(f;l)drm(B3fpG|%dAx^_$g;V~kV>H_R@q5(xOW-kUH*os;ajrbW_ril@X^O% zgwin&9T?sUWg%lOK%To%ypp$vk+7O)+hbCeE^^j>X6KPv{28@Q?Oprli{@;g=}R2l zX@hp{eSrPXlXMb@dBHxIPRdV=C_5rC>gE$a{kkcf{wwuVo|%u0YuK?;uB>z3j_P>L zAo37tBb~V+E>7xb_c^#)8e(19B5td^fK*iy!xyV97S(}hLl#ONntp_wiL~?#42EbM zooGatRA~6l2w_l$s1k6y~MT!5H0gWN0@2)DJp%WEobcntC0x+ZD}X&qZK)n%zL?O ziLisZ4kY3*Ffa3uKjW|bwN|Bc>3-q3*oDBVfimrRzs}oos80wV?q|**Q+<6EC^xgh z?rgI`fYo?rbmZ>5pr%x=*kk~zFxX$+vEK>=vmHC*YGwkdE zbj7G9TUxc>)E;kn{jB9n!aa^nI*LDz7IIljyc%cHvwqtZrKKhFdV3R}Lru;jx4nT*{r7Fn#q)+!-$r03p5CC zJCW*dbhWxIv1msuk;@=2Wkp(fk5+5HVKMRKIo*ikwJ%G+{-2Lm-^E3tl9GgJ%m^T0 zMX^IjSstTB^#P)K6|)z2L-vJa`;VZ3Yb4l1RsY%EkW#M8UH3e0r*Ji!M=tTEmEvi3 zoDk~a*9G`XOfYaLdU)^bK6s8L(S93nPPki@n9LSKcrPUt)C>souB{mDI7;L`xfkc# z;xK!S;%5~`hwM+;OLu4{@DsaQYLM>9qWVlsS~$VW!?Vw_jIdC5ULOm@u5MRP$UQ%Y zlGqTJ4fMngQbk}IdWx>*2plvw_IT*tEQgCa8>ZDZppEt+$8E~{%m=TT$V5N?Ej6V@ zNR#%Tx87;m>I5Bjgt)WlcJBt#L2k2R7Zi9AJ-x0!6%j*+#g1K+PeGz+zv<8{o6&`NA7ZhuZ>%q6f#xkqR&k4>nAP@~i_~5&oAEYM zr^sF`u-(seTYs{^ow@mX&ngj&JsO&-jSkRJjmUXnOXDB`{7uCa4(Fj%$t`aZ6qGOG=Y5|2SH!O%y}vb$41883kt8# zgp8*fjkmOK8NbUK^`f=yZb;jmro^LS_u)4#Bo-McVSjukG`Q2frCwn8TbTIANAP=j zC^66~KeBjxx$)N9l!z^pckg}C(!Kuk*0p2De)86B6TY%XjjLndgmz}6dCZrDfa*x2 z@rHAzyUaK0T1}>Ws)c<)J_$kglA{BdDRVt~+< zmYQ;rD4z%QETM|0Zb`=`S)N$@C}8ztCl51Z=UoMTVKTF4DKje$C0lOZe?FA{F&xgl z&l2iIqgnw*E0KTPs(<3e+`s$VqjUF0k`kX5aQA=u(!c%joX<7Zz;ax@P?%%R|M&ml zBawQcCT=)-?EmLo3Gi^P9%8)2?)N`Egnzu|uomLnwTjsCkH7JIh0RGH|MM$zSF?;r YDnxjTtNIIQ&%=L?$S534kkyFovF>p8}S!@30eC9Ks`K(0iXsKKxV&{Vi6e&c8Re z%aHhS(mbqwE79Ts&)vZFKTH%}Wm|pVkICZcE-JS(62Kiy5PVSPo}&ha$TIe<&&x49 zdT%e^4HORBvfxV9Xx?doEOvZjvFA>GoBH+fhAaeup9HOWWp2ni^gdZU>`&xRQp>HN zWLJ1bbcUGZ!Y}@X;W_ag>oE?0L+|L{c^h^Gc52E9AC6zVihtb1MUykY#ekf><9_dA z6c~_VzZVzwn~%@Ew2oXU92EKW;Qo1A*2bvcyP0QguV^VFSSs_C;lFyyKjZt-+WhP< zXUbpip=hYU;QJ+$k%ja3;tM3prT1{w2o$|0h|j&Qm!)8otVJ z=-06;@i~KeI4syX-uDMcHhg(p~P(JYPgL^ch3g2 zvQYGzTB^T^5dEmwp5($0U0rhnI(vEyQiCy zz3!RMuF7Fp&B*<}V#fA)Rp9>HdCsT2Ptr}V7(cxP|v^x;DpD zkkC`zZsGl|*iR_}l1Fk$`)4 z8jO}K)Nq5Ymrw&;(~N}fBD3n+WE;YykBNe}rkBI*Qo)Y28YlEsmvr*Mk;&9%ZP6|; zo9R^w`EeQpTHyTEMQh3^;_a)dkjb4J1}xB>xWsZpJrS=zml!Xp|U&4W7c z2cITr+A^xL#9UxCV&R^#gH2_kh9zpE{k8BSvGDr!Z%HB{8U}P7nxD{OIH?@tZY33v z$V4T(s|Z;}rz@tKcNF-ISLZ_c`Jd`qWG2uAXr4iX?}}vE9bC4h0nZh zvT)~1PlNI%%M+9F{afQJ1vr#h8BJoBfr?yfsq*y6DqSpYN07j>JFKDZZcVrAZZI+p zX_U;53*@n6p#jGmM%r{QWx2J+bWHqlI=u0YW-+zx6}Gd%+hjwQBGn|bamQ0 zsF&MHiV~eID^93F4iJ zh|>5w^d9!KZssHX_-1Qfydd zqb}?7w>xwrZ+GdQ7rQt4>71SpVSY~#ztMzzC+lI}^tRT^bhh&juJUS_%1DX|lm=>J z2db{6$F?=Able3c#JwO~r2?&6w6=dIZC|^YKcPVSKM(ZJYRZx)nUIe86K2Q9akC96 zdf$D_Wh7vCy1O?_W@?(788}tms`wa~FxMlZ3Iv2>y|f{ewkie$mCfa`GbBJ`Zn~L& z!@~cLxh<}|+`+;XeD4Fzw$J?Qd)0!aosy1_*Z9VEM(mHXOqD-Yo|pq;7A{px=+{&J zJAD|9YS2bQ&A4m1cIyDMc5{U|7q~cPf1*k1dKhA^RIc zoJ?LPsqNmiRB1!X%~QpwHW9lSEQdBew@~FcTy<@eV*``e5ULWw_a3Mi`c4;v^M@OJDE(15K36GDZwvdqO0v9pA z@%>z(xKaK6HyWO6se+5C$g%(8#xB;pXZ9O6sw3>+_I(38p@m+TXe7a=SH@evi7?Y8 zxses|Wij%2<((<+n?JGaIrpYur^DsEPWj)nQ~DpK*5J|T_i!l>PJOp8nfiHN(gC5*}F1VprVeQ)nrK`O55JduX+wck~@V% z>v)i5{P#B-?;ZAi%fVJt!#f8f!4q6qx`-*R6~-IC5vMDvpPGw-Eav0igrc>?@N=7e zy2%Otn@n7fMNJpHjz-@EURW_EKBcp*d)T3RJi$&RyG)>{xO=ulLMuvwMP5i*O#dQd z#Lbl~U6-g|?`iuFXEIw$V%QFC?#^Y?z}EGcc4Vui^0bPgt1yxrV5xeje7YWe7|Wxq z(q@L%mVgIl2N-hO?TPKG&X(X4E-M{IeMz88neAr~!y(VJuM?EAftelT_K>x)Q$4wiuv8G#-+H8cmDu z3!wnBJ5zNfg5~BT+F$1>3ZdkaLGX=T)JYKUX}aDPqn`y@xF^2hA$E*YWykN~GN*zS zC-IWQdOk`x3Nu-GJDbK6$;90iDfEsmDQPdnk2+%2PmlJ>FGr(I;X=@+iq|Y+r!*?( zvU?mZwDr1>6iCg?ANe-SQ7wbyf@^l$DHI7Cwb0aIs$`a3dS-`H*683Yqpjb(t;aNF zuEtRP`p4H&?`|1EVhIEraok)b?J6E0>j#$gEk*mX4Ba|ITz=&pFfa`vmee$W)37<~8Lat` zn;}_gdctRjkFHld^-(eV0flEb)G)~Jp@MBUI+ja|Oc;ENcbPSQeF#2#<418i9o*og z=H@BOFAoV!@L%PKKRfz1kd%^vC~Q-H-?7(nlJ(>Wa$d>YZJe%-{UWT>`||Z)2c57h z#!V%H{q=L-c#^NRY=<|`&IBu8)_=HsL&1vZ-1Occ+-51Jwth(^(%qB)bA_qKqQbw; ziT>MFG4OkC6(kac-KFvW0nOX}vIvQZ?aySS&ycmN zG6ewK_15{nO~(IrNB^8oZ3?7j_^Jj^v@Cyil}?Oh$YNWVvvM=Zg^QJK+%1P1lRICQ z>+uKY0oiAx&)J;8x2m3o>u=xj?+`pJjHZ4`y9Y~-@t2c38NBK_J81hyC9e-P`^_lg zO}g5y2DZTK(?1%a_=bd)S`$I?c6Yjz&%aTJuZY+8$8tm*?z&7KZ?>PWyb63&#U+ws z6g?yc=$cF?JL`T4Fg7z4BsL$+f zvPQKwTjl$szfzwsey~b;dV<`RKdjtV6r$~yueIj=#*Mk0 z6WZOig_e~vpn`GFN=v)(K(5>k!}d4JBMsidsmcpuY56B+^HbI_4#IsG(cG_p9mUvh z8WV>ev_im(7S3Sd&>&^z#?W>vv0|1}7_%ZwCfEO1heRdCi+S#j1<_29;g3S6>k!HR zflPVphltVRwLv-g;8%s$#Ekp?JU+_Zu7pKk{DDatu84?Vc6`J{ONAdUUq?Cge69$- z!u!h*bB6fEjVIkOwm4`GUpBy~xY?wIgd}Y@ti(!B?^S1JK0wfu5Xl-3rZRvAo{)O( zKDQIeYY{kYBL}Vqzn`pn41||C@D5>*N6g!!d%GjKuue~vc-E4I(?lX7eee6V9r{?; zr9{f{sW;M~BScszIy#=#vs0d|{W4{P^REvFR_r9eXRmr>GW*Hb^DPKCM$hx3XK@g; zp!USAe|Q1-!7>G&>}e0VfjF`M=x+sG%S>+;O7nG!t0mnwi9JAAFv7G8V?vL&Sc3^| zy}x}FuRd2SHaXb{SdLTKb{Tdh8TG~5IEWnM*DY-$#y&}rPH+rp6UV01z;8f6d~`zY z@nX^mF~|p;7KH)pi*)c~(dF5m&^i#Ll=Syu@+*CBOcmxfuc3rbhcqIcuKZwDUBvD< z=DQ<*=K)4eZ2EZN!HZE^0Lv<9iR-4St{s2dSj@?(qR}kB%Cu_hVrhVm3;yaztYPvIAq?EL)IkEPKxGt=o$$`2Z1=i#xU^(84S(Ay4bDbZPD`RqV7X0 zp9j(aU5-#tcj0K+?W3PXP?Ug?F_n%JwyreJ{KqPnV6sqlu)M3c8R3)pe#w6Tc!7K> z<<^es2iv^gt}XN&p^de4+JE~x+@AneI-P@CL6|ap9x8#Q#N7!1WlhT6QO#H^4ikE3 zLRt;#JMqPFywLN7%Ie|wLw~FYcGh-1W7?tb_X`}zs(gr~+(tuG-Fvw^_Q&uyMq;vF z&UUw3Dg@R*R(8E(4MHu)6rhfJk)#)+vcQQB#J0KZltg(P&deJ(7IE?^8^I5GbFy_F zw&)h~QuM}hUUrTuw;-g+Y5oTwZ)-=62F^Ulz=`9Zt(MRP=bT_q5Es#-k!dkz@2k`U zWP)+e0maqFbL&IStff2*Zsns39POdO3;|@+;TIysO(%?tD%#&LmdO=C#uZFohZIuu z$9idHP_hLrR?GE}|8_Abq+KPvwS{*@HEu{Q%|(0m`dP|~y6%Lm$hKUwH>`!r)(OPq z@=MLWOtqaQXG<3`HXpql#$q_r>S4ktU+*4L;$ z0*F+KTmmpQ{%#wliI81-2NeMpP8OlFFC_`xxxwN`d9p4xfe*bVgEq4rfmI?F%*bN7 z-?0|Vnh!9jbfF6G0MO)<%{TQ66685F4POivY*$BKL#scy5A!b>K3y&e@a#|L>N=0W z6e6(yfrI|&*B3)=DIwmKP#A@^kQV_rKW!InC#(!J?G%8a>Zpz*Kf(BUe(BjCXBlTt zg1nXE7)?Zsr%;!}tht|@a28`FLd_WKCYxot`JPhM&_aU_zc@0%0z^L%UZ%bQa$F-y zUHBa`KlP?7Z4)8SW_i4kl9QLm!tZ`IHq4?RAC&#K&6(4uD*MBt56DjobKs) z7)k*03~`r5yyh0c(IcLF&797Qz9bd}EPL7f7e|26F(=}1*XLE64yCH~24^~D`66Le?eQ~_j*cCv&}=kq-+;WNIpV2j)6*0P|#$rtfr)-1hr%Cx=w&vEIY%KB&kZrB2Bb+q)a&ZH;ep}p?miBcb7qIoC5Hxi;2@Y{p8J_yB(&L2s=<)!G4uhL3mU<<5EwLYNrl{EAnxO=`+ ziQb%sZGRwA+{vHUEbV!g`GqdWGPm)WUU?ng z&fk_gN8;-kW|B|_HeIuzYCRdQEGQFdxT(iRn{7hs*bYjSWy!Dt+%2{rMjxs?(k%MovP%CQ}eS-z;cSV)X z)O@X|vjj$H^X8I#nC2D#@6ma?n@9ZE1?gnFMD1GNx7n`{@Z~{ZNuuvYG+Z>vq4{hnVqB0EY< zs%B?iP=Imetszeskz~J!9M;!PkwdngpY#O3pLnrB_C@*C9h%0a-3cvO+%$w+?3sYfx<#C{iY)4m@JT^o|9BLvzsR_ z$`FT}Mrt_~E3b$FXov1hgB2Qaw(ivF>`!M^A=$ee?LqY;& zHokC*crEnSFBcW>SKaaXRj^J500#6uAn;<$5D^o8*pExmL)43uh zvN*r+C1pM*x0Dj5RT|BC*)?DYV5#y-j!Fo^^A>j6$ET2Nm> zY$~u2;iPZ|CiIA|m2{!nZ``l!Lz|B>=RJp6da%&^wCvL6x8^T68Tqo^)q+dPisSC= z#qcCuY9?~ssS>e6Hc4)eK|RNBz_tS3^a8TT;19t8+5rvgv33gipxw*fuas+@M~fu4 z1{ATFlOqiFW1?1|K`}3-G>EX`k2A$ErdWpTv2Ux2{-Us0D-Y!N6kzQzQFZ_9uE>88 zoxZRpmitam;Qr#98mNt~dWrEkRj18;y8t1sxbiqz-?D@kJ4{#M%yN8P7rwZM($7(T z_XM0E$3GV5J>h5hXQ2-1IRWMz6KHZ>w9eIr!BObPGOkC%cymK)PFM_b145v zvua)FQ8mx>F`*7Fe~gvCtXFY7{CGvxb4JaSK^jxpcqz88^l!~k$@nBk>5Ut$ItgnWLK3k=qAV7_yklZltd$;VuRy4%~SjzZ>~HLg?Bid z7&7?6c+W7CR)R-{U~e5VV=^Rx4!7VCGiDayOWWAxGG|xi9EO+L_X;~tm!#!m(uAVe=sh&*()0PXJ+_Kda9T` z{dxocRXgO?^mdt_TgB)R0WFLyF-Z)!KUrHpc7GL^fAtq7Ms%bCS$p2N9zxp9W<;wj zK{TZHsP7`|&d^@%y%l|ns6jWD*OtSqeZ>>mP6jG(la%Pdee-|`)FQ^GG(#lB+fF0X zI3wJaJFYZNNgX}w0cK!{=j^Gv>cFI8_}C>a3|Z-RZm1z3z}i%XproK|L2#+va8BD0YrczK@%&==$gcis)194kdHy=4ZzKz$hW^dJU zjfW?%7Nfko(iZNOn55U@Pzyet1!cV|Zki^w$dS3KR413Bp30+9z>i(jt74}l$5-Vh z)ZOEytDBjyQE66Uj=E~AY@lo+m(u5)PACs;J`N5v&m{POAokiBw?0Uz@e1sBSIWIg z-=7G^Jnt+OaS9qOHnvB&MPD6u;Y>j+825c{qMgT~9|ZSIXhY^XHyX^ud)$j8N;~zO zIkRoj`&Zxy%mIJ%OJh5=&hCEI$XE(tzic5=|x*F85yqKYt zvcl<&N*=?x9Ag94@a{?;gCwQR>aGH_QO5A)4cD5(&@g~MbVjShgHMiLPwhXZ`m3kx zc1g5Q$sc~Bz%Cb;12pkFi1FJu{y}+8(Dx6KvqS2_@e(cgczh}%C=a1#8HDfjKf+l; zk`89+TNxH1p&<}B&o2&WR`uinzzaQenSJB8M$_4~EV;PM;$=T3D2v!b_VcK_m^$eD z`6_Fwh;&a#=Zxq@ffv99CH*Q>U%DB_b*MN2n5gOnvl?8@Vd}~G&~j}VaIt0A3OILj zN=e61g+~Eq{puR}oSIU=a@y(Wp^e_=7y|d(c+;stpBgxfAQ!5hIDMcTKfWi@Y;huo zKHd(NDyuS%K_d0^4Sf5QVRDCQ#Kp2H)%-Q)=1HNWDt$OI6IBWFkIF*6=@!)5awz7E zjLwqQ!anf5`}lIV{2wlS>1ru4xb}+9)(G2S+(u>4T+g))yS*<-^Lo!Eq!IUBO<&yu z+Ysb1uL<;3I}QE!=E!mdW>W7##>LMm0QJ(Hk80q_8`m8^-jah57PFzX0(o(K2@w;O zjs^Wnw&o_ck#n~CZgPx8s8)AXYjn|}rD6f^_4Iqiug^J4OT`Qhn(VvG)NZK}?KGsM zojQN%qTHM`T{zHXE`s-60y7A8C78Ta)8XT0`w^w#w0=j|f~ft*je-)v*vg`fsF=#{ z1z(h0gxEB5gKpD4g_elgJm@K2%wN^^^4S);i9ZhT>=wzvR)z9k#4(OXwaFj0%Xh>} zOf#U&{mfSyab+d7dNW|@wJ-MmQx1^e*^M4y%-qDA6K*+tG!H+2?0V3mwCB(RZnq66 z*)N)A7~D^l3LhJvpu^dWoQB$4(;@M|{B{SP8x^GDFeerJdR;)NOee}rWrD6MYh~X} zlP!@K!Mn1X*3LeLL^vG&{;8j8Kwm7V1$72$19JMtSh_d+8da zCKS=UcN6Z~^)%2mdPoQK4W5Okx?fV1RD`l+Qxa-z?z_xo=Tbszjbj$>38hWMK=Vr9 zx{-IfT`L%rJ6$u4v|eR_H0U!RJ1eQev_m!$U)ytOineP(kZB zX*4J^uRi-xg2xHL17A}fEGWHDR9x0=pHlO8d)R;WDEz-9k};}tdJN)y#DRc~DaZX$ z@cYo!7?#(c-jQAeg^}(cVu!&jERcP`b6O!kZYtWA5VDoyd9Yds_Xycce<$U$jMSeW zi>hDBOP}rLFOO?%Y}^Gjnx=6s$o@z^@H7OVozm${d$b;j!!G}-v0`lcoL10c34?sz zExDaDG?{a{(blYa62AL5y8bXYvRDp7k2#p8Z#_9$x9y0c8V^Vn zcblLa#j^imX`_n){sz8kKxMfJJv&XV8+#sx`%|i)~Q)TfKjciG{vz< ziyv?0%PR#3AJL)af7OwLPCva+MibT(?{QZAJyW6S&=){peJ^jPwB=p+m};#p?d}@1 z{{luZF$0#l+22fOo|6kjwE{%X6YW-K_es46NqWjt#x-EtvfKKTfw)prgYj>XY^>_Z z0@1;QafjmPHKwDa=YP?6H}=PA{Z^I<2%St?;O8cy)I$X?!Y*mO;3B>?nlC z$0LFr>*UZ^{_47t>rI=pP&jL>{K+0dByj8dH|c@9jN_-7>%TRqg3Sc2MFUzQsMu6? z;hn7wAmDq>MsowpREvhu?ZRK1<({<>*a3;n2Ut-f>36`9MoF`rC(X{F@3nGQ*egiwNRgm3cy;X z5C5Z`Vn@9=lEv3p0FWd4jd)wjxg#gc*RB0O*8hw)gFIU@TZ#DE%vt zj%@ME%gcXdD6Nqh6~9qg9OQ708{c-8V#}p%cRs}uj7^Z2BMZMb`K0}l=Sdf zEIB+m1$#&jyyhfC;gHZt*qvlEqHsT7t^BMl>q170F5y7Z02>4DqF8%I*3H3UM-VoRB2YalDi$b2dR zXW?tR?H62|8_e*fB~NbtX+!T#HyHBL>iS*)!WM)aZVvK*xH)3FmY0et(xt$HSH04F zd!dTD`e8Lhkh&S@p-M$lb$I&2}sO2!&?~ z+JHRO{G;Tn=T~Xq`Fa*6D#^ni?Y85Uc6cC-?83+Z01N_Tu$biJZy}E+O#}Z6N2?)6*l`xpojpzLbY}_+7#c)UtM!Xl)vzANpum(IT+SDRlpccXd6m z`9q~_0xjM28Q~Dc|AG6kwgKoBzTWo_*CNlu5fImSVGP$rSf6&x+$`j{$)4QV6L^k9@lh6y2%#(mE4!!>zmp+R zgD6{2b7~apxy)N}s+d>*{y+RH90oGwo$>$%Zspi(*;?gTE&x(A}&A=UmYA05S8ZJAKi8kdQ(jN=;o=G{pJtH+qJC{kZESn zJ^=~olPx=V2Lc!7`xt@D4?wk;`3VThq^PQ-L_k{D+$9h)vF3Kt)$JoMWM1|Etm83p zfDWLC9!1HUd-(_X8G0S!SUy*v7c?A`+S*8g@rdDI=FlI3=IZQR1RP-Rw{8{$08I<= z+y()(&YKK_&Xg&5mvrPM&+Epp} zC;-QMr-2PZHOhSyg>v{bmZ&Ag+YeATw{agg>hDHjTULp*{D2szuC8wA7uYt?FTFll zzFP3t7o)g>6#@qg0|El#nD5+TWMsT1ThMXupO{J5>RqeprU2-ZZ=Y4ex@cxsSV>lo zTUSl)HF%AePn8WvHcKMDSEkE&>T`j%A-Lah_I+Y8L<4l&n9j@C-V0 zzV><>n$2hHBDsgVe|OtOJn&$MnqmAHrRO21ShTOB- zt)kn9&4oER*d$Ct;|X}wpbWQJcHZsdd0lT=ot(vXvBuW*QVmPEPpA$&VtI`(@nU1^ zTA+gR1m?&Gb+C2-lGC?Ugl`#?9lY0K3UpLOG{R8hXou#ShQj$kCO?nuOLOgt;@)n) zvRNEc#qX2Xfcr3q6Abfk@8W}z&8uaRmRqhaJT+6z!ok~B<@g=@x!hS4Jh0GR%OX3HUMUYf!i|R>S_1n{ ze2?YvE%J#=TN_}%CeAfr<-j2A>v~FC&Q87GCk57h-lEH=x={T#(iF7%kc^B401Qt+ zF|z-JS{lxGxElj71`g3bem;;DOxgqh%=mg>D1ac?HP||shHj%CQL@ya;4 zP^GYc>j@@!r_WwoRh0ixtp)qJ&7p@{!@U(wT}W@vNh<-snB)!+5ZUp)!&Q$^X$DQ_ z7j5Fys^3tjqRDtlvTVv(3YnW0JB_GLU=~Ubw-WrbNk%md7NAA=V^Q56}O1b zEz9GRluoFNFQ(Az>*9^}=;d;+d{)4NY{@=Fj}oJ{ac-`=N(buyGDgd@X5#AtUU$x^ zYqj$}YR*~2NH(rx20W)6f>z|f0F(r;?V0R|5C|rSK#9jArm{>fqUWfFUFXvol_vom zs`8ae;|ce<$ATo{Tt7}_cDK4II-r+(5G1~8Huo10651j{JeK7^wuof$t?`95%-99- zy0Sh&$i(!dt$5wxldG5~SK(b{OPAt3y%2j=hm$K8uw#=V?rQ;zQIM07NN*4IeF=e5 zph--AJW14Q70%rrd8pmTb+M9?q5rhQAsLPfmw%nu3JtT1`T#nm}-!25DPIqq~20iTYW^1QBf)15(TptiS z_!3cDSlk?(>^?L#;4sxgk%Wa|+TQQi-C2J)J`G+9d9m5GtT8`S2^E(Z=}IP40Rk1G zSU`4;qp$KU@^*2+qhW!wb(j#4fMv^JC^MvmDQF#pVOj#gZm0h&?4Mbi&j0E&%MxgY z$)iameXwNljr|}RNMPHEYNzodQm1s{3Ma^4LAxjxwzZRbx;D*LimhCIevZ8IyzECG z#hz1D1OkXQ*sK?q8J*h)A#MV|NGH*8x^K1M)>p;A^P*{n+R2A&677f8Lt`~u0t-I; zd{3V+Z-lpzr0?n6v5QTB+a}1;CCKeN5|4y3o? zFn9&v8+B$8C}vj6z2UU_jWgE9Mr2{%xL&REbbSXLrn!sjH0yz;n3GK4;rBXzD{6S6 z`+(H9m(-O^&xVDSlS}FAH@f+&gmHQd+j;5kFKY;!Zn}AJrOD-iwulJW6lu3#-{`Vfx4am zXw!M>CNZ){PU^bFfqtA@tH***trxWX5E27$K06Rw z*|A5sLZgJ}IjiA`qch=4(qpHS{DJgivbMDvl!fVFjN+fq9JCG4sd9{~um)T=EpORh zHVU`JoLUAVfo+f~^(B)F7rDczr$zVy$Ihhhwl%)fG<`NQ)QMHAT@)a^Lmg*X!Wl$e zLV|WPhG$tkmJTo?z`kOu(xm>0b<o$zB8!l_{FDjs#4e+96M)qahm zCn8 zapx>T_U8Rh4lr!mNAiSzVwo763--KU3f-d^*sxAkJ^fBr`0QmtlKgs@G>u;jjUbKi zmG}3YJY!(6U_?o{wZI(tU^q|H z;2vE(N$-844D(Ex0GqwfC)TQ86vCed<-aB(eFeOpNs!);p?PqHTdSne_I?7ZdGHO@ zR|>Q6gz`qkK~)6`5*_{XO69t)YeTu}bSY^P9zr!PsARxLi2J0uuRwhL&zC#*ldbQ% zsnULBCFU@KyjMK)9lgV&qp7vC+yiW3;pFscC&x#E=d!LSJM)%MC}rquge6PONk%eTQ>N>fK>4~dtl9J(h_pCzp*i|e&^|2)DgA+OLJnN zap)(Rpvo-nA((@Br1#v1SS>8XNm z10Fvk`{TkHSEBw@QI)>%$1OfMB&k%Y>&yTvv z7-kH$dGP7^xm@69(acS02ZmL$w027w%MW88YPTdg9d*#xuA;oQy(8tFHOPfvSvv84oNELMuBrY)l&3smD9QR1zf6VA!&$1=HvCQ_y5%~71yZ}qJ z_0j~puhH~Ugyb?Hi(ZB+bV#gU|MZ$^Xb<*Q4>pwV8)@ZW42$XwXlw9VB%!@;+2qd= z78bT}aj0F_ZMw%a$gM45`uLmM2fITp&N=N|+Tp zr+9^!t`7R_0q39T4PS4^}eU&#FEnIeoQdkPO^73(DVZ4A{)u58U5!s(5H4 zD`?pg^!&)M#OsN9UxrbH?TcsIj7;|{E-~KL>0IP_K7VxgXOWy-sSnz#d}Mk6jMF3t zpNhl1&Em_B_}NZQE^2B8MN03GQO3mk(N~nF$dmXCZh4MejQ{gvpOJi4AqueNDGQHq z>WrmN`I^Y>70e%`8c=)rg1(23hDDRVaQfoGgPp#F$DM^KQa@sZfQ+brqwo>6e*Jhb z{mQ@`Ilf#$q=bJw%~{}jN!CL|l>=g~E$nPwOrPl|b`HlMGoP*iYL7{CU`^d*MQ^cB zl%P@BdyRDQKHTxZnJZ7;wlxK8e$om)-B}UQ z{LcG5$vt*T{HXK;|CI=Dr(`wf`-FujP@FsyVmLDzqkHvIlKBsIb9vq~V?hTWa1zgn|EU9xNV(7mP?H+f<wSbdLl)kUSIw*rEh5=dlP=&P8nn&pQ^G_>(;BbC_V7dRS;tG|S z+0IyJc`_D7Yp6}m2mA$1{IIVNkvBtl`gWcn^WG^|2nQ;=VEb{`h7oD z_DPa!&4Jwb1k793zK0KLDhcujx)+(;=en3@Wk?QfSbeL-TmH+OPBEA z8+1a~y5$BR5E}7iL3|48o``X?}=@6Q3K=d5>vKi&xpQ6ROscZeFY*T`~6J* zwVxooN!f-O1=v8bjTvRvWmcInnNK2DAlGy%r#YgjrQejKzE+ti2k|f=j$sHbpyqE< zggH`Js+Cmjd^FnB*Q>eMS+USiDFh}V9s?@xE6@n+7W*@VSf~6V)sy&=s-1?Ff%ML6 zG*OOcGzk7?eTCfpyYC)h)pRt29D@&C#Y9rDB?IihBm|5J-TiTQx;3=CMK0vfac}5? z;)vBzIMkvwq_m|!LpuNEOQ1{Y(*CHhCO`3AotTHwN4>_S5y?I7dnclJO*xJSK&X_@ z;pDgpODUC~Fs;lnkgv@)YQV1bUUCC?ia-rmg2&HF9gSQ)bN$K~nUBunLV#UJZN6Rm zN9#Q%WtI;ybCb#;=XM3AjW_b4AxF|$6q*l+aNRHdxTFVRx(%41A%XphJF@`prQdS@ zL+R&-fhiU4&H;mD;iA|I=JPi8+)b_vBh&8P9}@_e4>`piAz`cQHjo-Du>dUVhOcq11-58k2q8Gv2!Gv3Sx`?zug4rXs_ z$Q`ddkF(ZW*4LhC(E?yn>s`^#jtSa~2gr=91{Qz)C$C~Zql>GIXOb}FsSv7nLyJFn zFDWwk>X`~@R*y2E?ac#O?mP`3VD}i*b{=>TW2=DeecVsL-_jxim5jCCJ7Z&9`S|Nw zc5%gsi-CR_$4gN}F$r1z90CAVsnNvBhWzsx=}eMOAx{7-_j!scGtYHH*Y;C%hyv(( z#}@eSy2tD%o=5xJ%c;@IKa=4)r5v$hu7(HF38rTjl+y$3ke|NB3VjxvsQ zNM;=z*?aH3Wv`GOilmS&dy`Qqdn9`$lAV>2RT&kLQp#3B!v8)+@6Y%5zpi)J)%Cu* zjMwY=yzj@l@59kuov0`BK>(^4HG$ab)KeCVCvGCP;lBt7Lyvhz1n&QSI!|mT7oc!E zn6xsz*mx1I%=a|NsjT@CxhH38+QU|hW#dU7Ei6UYuQ7gk>(76o?(&@<-^R4|e=YI_ zw&$I~*r?b5&Jy(9aOk_kl?H(SuIsM8}(2NKjM>qoC2i zt28K3B{4Rl-y+=*1}{O#zi55y5Sq*5<&n#;*hdhZG$O^MD|4TJq`dKESl975#(m?H zMu|~LO80lTH=3Q1BqTJ17tS7*zdZ{1R6c1T1*IfbE$SV>at&un+6I(wDKg;*EEQ?w z_s^|MJXkM1@o4v@%Ldd;e%g@U;rHrOhEFcaHwhb5-rHl|pz2ItI_@sa5IqR+hv$jg zG>X9f(r31{SGsb23!??|Anbi6yGubAi_=JL&qPOvP~Yb^tIo~)T~vGc!`mS6wx!@5 zTWxODo7Y_ybej@qX*hSrOR>F?NXRl2=LQ_(BmeX9v{u36b;yRFEK3A z**-r11~ZEj0$omHy3uPa*(^h;MpAZ00w*!*sI*1D$doWVPD1Bk86Wnbh&+k-^-t>STU*}KvkWnaDeYY47Nr#KOTy=cd833a*X4uS z6a~sNl0AG-YvLj7!&X{ThTa$DcVBOu(~q^43BrvRWRgUpeRqCsF5d00Q(eyricDw+ zGU))3mFvH^*Q-g|Yt`G&A-_WCNT-SA%69-gAv1Mm?9l^^QnREplLY2VrTl9Nh8 zILW&9d62#@OX`WV|IZiKxf>(${^yytiy-#*cdr^J>@2@~k^-jKo7TW4 zD1yj#U|bIXJ#1{R+k35^yDu1#`R`d}VuE>d2Gd1S{kK*$pr#-~C%a;n*__2CNXWzp zL&8pwnWt!H2w!4`wSvx( z)VAxD%mFpszrPhyITsMp^_`82eaS3Q-$(&H7Lc=BttJJmU-G;!cDCuY#SLpxt3Z3I ziLY$HA;S>NaYy+C z?rE6tbIhOXxQ35cq?47xXmOPJ?@WSj18>KCYb zT}PbOIV!d`x8#8r+%9JE`u6&f{c}?4jM@|0YHiQ0Fh4Q2?6aa?-;5Z2)l3iHSi3Z$ z`ox>In>SCA|6qZOAg1dc-}M?1J0XK9k-Np@q3TF^z`FIRck{`^#I$G0!F;IbjZbx5 z5*})ifjK&w)Y{IcaJvs5WrU>f#)Ia79RqL}U53!K#^iWl9VSgTc@M0%9q0&Ra_RAk zd&F-nne}B#)Vcy;77IFp-6(#pkd^7CffQCPjOK0jP&Y&j>P=Oyg9&x~fB;^h=A9Ie zFGJ@^9Zk)iH>|TCK2!I*?eJU>WA{e)(7;w71?*gRike-=%#w#t^O*MniodOQB8Jo~ z?LV*`4j5j~{tWf!)m1(gwM68ujr6PA2)Fmm9M(7Y>H+|EnLlykF)JwihcX(naT+sE z@>yB#4Q2^mj5R9Od$yVCuAD~MaPy$moD9yfwZgFsjs^yS6Mx?w8kac4X*jz?m1yLa zJ7b(!WHNy~GUI0)ji8HE9kJ|LTuy()~g@BAW?@_R*ssn5vq@XEqCk_E2MFZy0dF*Ss$}RXk^bVh7HM#Rt zLyhZ9>xI2DDxK^Gp9Vi%#xtXLdtIDNM~yE8oMiPI$3MYg8xsN?%q;dk5{MU_sOv&1 z1C8ezB9fGm6XdQ`$c2?MB!H1eaq=Iu%OLPv7*P;8-Ur%->vZGTxmtHKQxuJ;>%Brs z*Iz%rUIboJ$&hXT@3BvkkI-=_15!>pMFnkKkQsNHl3jl*>46rbp(C=7)0lcH)$j>N zv)UXxR;Q27Pr&(b({W}XBp7c1bTqzkF5o(z|- zbsYTkZLF;Hn_L3ohy3h^&ZrbFQ{MUho&G}?E3lYHa58!ZRfV@Pv0@jwKp7O5Seg z_pr6y4avJ)oZ-eW-J+xxxUD&t*}_%O^f0Z%mm|`P@5-@TqykI8rLl$Rk?R}5V`_>M zjI6;YOf6So5U_jH(1(Gr;SLUJ1sXZ4fPK$x2woU6D@V_c?}&>Zos9N21gBAPF6#UB zPrc8al-^V2p@L~n6QvtEd$LNX>$Xw`x`>DKECFn!2!3y&!VR5`?B5Dj%}ag`CJi5p2)y8MZ27v=#PyL zQ$vHOIwO}!*FtL1k=;E5@B-nwu*#APD3$9MM55>)QSz_iw~)(=v|%-x`+^r8z-IBg z78i7MFuxLlRIT=TFrx@T4Qb0KzjRnaW(gby?w-q*4J-{ZZn|+rp~&p09wY_(6UNgD zsY1xA>g=0_YXuI2>0>RF*FAHXMyjmkcEHazQv3jI7IXP^u`H$3G1kKeuS>BoSyLdt zMkC|r30*?2snd_BIq}Q0(+jx@VXs@juE-G&QFhJkhW7eRM%}0t4eu3&5M=Hl>-Fh2TupP_a ztu*|S!C0}Mn%8n6?t_pcBdQn7+~SGO+b376LM_^Y zTClQQW{6;^J4M5d<#Z};vk}3bPkpI{aFsvMrLv{|y|g%llWf%h1WT;jS|!~VM)C}* ztYmiC)(KG6N;tbX3yP7e+uY>j$ z$!;BkN?avezL)0hlT#I^d~3Qq2> z9=$4?de8K9--GvGS*>|vZCkugeGPDow)I|_Dlwn>I3xU>lHIuUHuw|Fkk_HAhM zRtTGe_RIw@_G3VSPa4b+(}L6JwJOAT)bMJ_L1BrcV%L+8011mcZnA@WU4V3geDd+7 zRL!^HD$(Q$``aJMVkp@XU5dJk|2#Mk zs^J|dQN;V_Ua=ir@`_A)A;cz9`BI8a{tMJ9T(Av$e{J$u1hKB2)OBq??i^ zX~%h)Jx*8KJj27H=Ujm`P*VqKF$F}5xlol-Sky=r)Y#|dr$W;F-y-o20~9W~`Hl((?~ME>>+sL?5a!RdI9OKKlJ9#vMoLd}yBLBAWI zkf`Y8hN|LyU|m~&GSd&J3V#dhJatGh4F8oX!EhjmXa`(YX!9&Il$i~@n`#U-D*Y-7 z%U?P55`V`ttHf@fMW~)T{PI@l;I4r(qFZ9PoFssC8#kE>F8>L)B1QTH99#=r1UnvB=U7OIwj#5uJ&eq0jl`JK&adu#s8S* z=L&I5;ChJmVut>PL#?&LZM#YL_uQ&7jKs2Sdp|S4$BW5QOz@+~`awV4ruXzBtfJA$ z?(5WO-$dvU0@!_9O56=%pQRkG+R=#wI){@@3}u@4%G<}uZqtp))P%pI^a2Fg{DP4=QX(lSu>~tr{90(Yl6FACAeA}AfqY+@RCfGQvi^q7 zQywy_0DeQCgP4dc+jD`w({!2Gd%Y^1b}#Kr@6!H#R<+OKHzf4`>RMR!{~Hp>iqU-m z`$&l}2O|XnEPv6-1h#XQ7PTgc>nU<+tn?1_1Y>ZE7QAjQ9F@6kI@~J?wNO@HmYMQl zQH!K}E;uFEe=eQ(`UE1zr?RTn>$BXa6^||{wB)w^UuD8q-&>Nv3FXxQ;gc(Jo<>%4 z7A&3=NROY~tH1KjD23@i$kc*({6&K5p{jvxrua`vv8hE0wXNeJ?d|d<#$|W?vY&g% z{P%Bb5wWNEcu(jrt!^TpJO7fqV`sK!&C=rM>@2Xfe6zb+j-;RY zjo@28ZouhQtBPW~5#7f;BNJfU0qY$N)?V|GA@98}RP@$$5sb*wQ+Z^vIyNBgyev>7 zd)DzCZhBzm@y?^WHcW}d)|`p29$zwqSAOdY<7|8*n+;E-ikc*qLH<9)>l4`yHmxxp zjVlx`YNi4w$1mKDEWwpflwRvG>aAHuC3gN-9JWwCyFV+i4d1H8kCpPQb`p@q25-g0 zN-aF#-giJMD68~@iZWJs%QN}n)6KqyAP`jrY;A3& z!8M{2B$Yh6_o}S?LBD+f2*m>{Q%^iCbNMy@!joI%!8G-g6NH5aFtoHAZm}^((p@ck z{VVOmR4mSE+0?eX;EVYl>6rZDtKFM~OuIj(DNa{)G2SiC$Dr7YIwi$(65x8yhA%Lo z(ZLSt?TZMwV-KhW7GIaJbViYFHOhJZmBE4$0SP$Sgrm!p^lg(M{s!}eK*{H*Q3jW7 z9=uM(U)dk*`dJ0M@hoZ63UgNQG)`w`8QxF8o{0z0H8hP#u8I72ii8l7o(pJ~iOM^0 zhOf)L7wYvA8vt5W2wZx}^I;R0Qq*5W6A;l31J}ik2|*AY-hi~^w&rAH%=e$m?>5Fv ztvPP4FTuNZ>fF{*I}+`Xh$OMd-!&jl^Z}b5BuClv3xwp?k!kjYYCO=55>B}|#pAn| zXlF)g?G{N*iq}KkDSOAv^z=aJhw~VFx>(!JYxMVajktfH3D4eGnhXu+Oy41NcyUi( z^2QQ7lrn*v)$w{;2#~HY(D0469Dp@=uJZlYi799#J&WO(p7T0OBj^zQro&#E7o8hp z3ulT8!UCSpq8UODPlI|pE#CP@4#|)l7=Ucj1NCI)q0D}J4KzVWYv67_{Az`V65Pvw zP();G8w|Os^Lol-N)RTo1N6I!b z1bTmev3`LWgISU3Z|F&PnS&>*dRqVIt#}~dxw66eG^Vs_^wa&(T8e!Jh4(41vZ?qhL3GTx{7Ia2|vuNUqdt519C7R>udAf0Z;6($P8VnBWM66SG%gusF_e46 z@#9#ZqR?;i+v)7ASNCIr>q(;mgG-Ie(m8~Cj@nEk+erNti}QfjJ(ni+E4oJm;@aQV zxr{Z^Wk0)@`oUr%d-N~8UI=T4Zu0<)2ZLOB-1Ci|C9;|Mr>ODBPD>}j@h&?kh*k%8 zS0n1*jR->kqG5A>j3t$Cn!KyvQgnpXdT^rL6QO%38MG?feVt;ib6`*sDEIi`^O%nU zi(lT_$M`OnlxHSgXjMNwy>b!UCM^1cUo;h?!3=W(LVpTgh*60_$)~4adnF?YeX``i z+xoOMb2AMpg;t3{Ve<+ZBS5o1|5>wC+jSEW5)jz1I#@TY>2$?8Jq87=51Sy;yu+!J z*{5_^a)J?-3b_}WZotTNTk+ftFp}N7lNdVH2(do?jg=`5tRw@WsU3Fw$fL6Uo+&u7 zT5f;4z}(^)9r5530%v@}y}dnb8m{%Ebb%K~2$(A+`FG)j-T_ma%hnX0gQet&6W^sn zz@;P#_xo86R~!X78vm&KD_hO0=e#vqP$O{3AHcW5_W3d4@P~YOFw}FGLE<`l5ws4@ z7!>Qvw6GtMhYvd-I5;OK2kW@WaDBkKMSiS$ujTYO@91z|Y186((=+q3EQ9xZT$b&H z$d_M^3qGO|{ap7P_3eFLoi9to2jC~N3(_o2@CeY~@DC&<#kGhlGtie6+PeE{2E4o2PIEfnR zs$Q^322lv_2$G@J_(QOkU8aP`ZJ&G~<%h@9ckT1^e1lP%2wDVax$ zqmVAcfF^R|me4EQ=G8$@krw&^u=$KkCjsI2fq~P!h;%w23xQ~lX1(j1*TYqoPZbsa zQ7bF7UfpG5i5pAza&u3G*8nf%3L#3krI{Q+_~1&aQHlqcZGJ5}KL&OY@!XLK*EVaq zn)j8*&keHXoQ=7B>a0}fTNQ_)W9UdoqZD9tvn^F`oxTF1?wyEsPy<;FA8HG_jB|6G ze}w5v3Z5XGl?Bi*-Cb?fhB|EA?WTnCX1F2vDIb!l!1cGlE7VH63qnU}Kd`(aHuV48 ze5?!z87X7d;U`z#jd#|1ND5KNvps?e(+{T)OHv$(5^9d5j}<~^ym%-Q1Mp?Mp!Iq3 z;8qB^*IgcSm}2VJNHbQEYxY^k0Le)KTMCOw z;R5#CtHV=^Sk=vz)-OlD9?X$z(|Y>!TdQ}8A;XI##7GD&zBQy=_!dxFuTJ5fL(;S9 zWTI~t{FrBLIclXIl*JZLDwiOlHJ@0MTl%!BZnS`F?hL!gKp->8Vi1$HPCm`}!bIwR z(;wPi!z-J#@Fb`27wuElOU$vh)81(`0iVEp1m|7N=;T{~F0|5gjaP5A!!v$emkpUk zDh`9L_aA=C5H@7B0}tkblwc9f`0@h@+{3nv(6xckvY_XJ-ll7`q6AortWdJBmkD42 z)BnC9c{MZ4u=ncw3!siKe|RI2b)P^!;2LBjvDqpRNSNWL&=Q>l+XrDx)L5C?kXJ39 zMjymzb{k5O(!Fr0qT^(rZ3s$EkkI|enL(#5!tK4AvsfeKnm{M=Y3)O2|8rRJ(GT^Y zBaWqar?PSN!Z)fDLYNSUs|>&b>*6!B+>vPbD+B6WdJ83m}WDJ%yJNF)y60glFd<;QE5=7UtLT zmq$Jh)EYU052wre{(4ZsaMSw%uFuEuwI%`myay`vMW!_{*X}I9ug{!j>VR>?Mh79{ z_|$)kx4YUlyjg|wUZU~3&dn>Y(O}C*z=_bq9>8D zOtRxT$@sNws?OuXr4XJIy!u{xbAU#`t~gN!pNPtxp*$LF3~}D_gkeadpc6ME6_T2O z3l6+)Wsg)@t87?pxwa=>)Jl-+;hm=#fw}bZ!S#g^ra%d`tGCzA?8H-bZa5y*=2ePf z5WO>{eGTT5#>&sX@=tVk#ENWLwu?qOXGKcSrd1W`BM0as5sJ(<@Qll~$XI(SoF2^= zNu%W49GXtuKja>e&1tS=Qi2ddzCNeIVb$E=Hv_P-tu?bitTYBM zokI^fkP&j&k(<@zx#mQ{$=Js<-V2xeX=shM37qp|;CyO;2i7S@Gkk<4QSRx% zcM&=Q<*yceLPTnNb6{SdZ#01yU10R5J3FD-;qhBvU8 zC~V9VR**cTZ~L(nT}Ok>yFBt*G?8g43;2GUMzk3nZ~@tLeO{9lLpmfIu#E;~Opno9 zPI2Q3At#@cRrU05LbQ(S|uQb6Yj zw+y|VV11MYXmAhd_6=NoL@#I_ZQE9nZP|Z&&q(t{t4l9U=Cxmn@`6sJUurNmOxT0G z6i0@63kTUgFQ+S(wr|Dw;@{+P@Y%?7S(0@~deIjE#W{&_xlf#}a(21#zIQP8qyAA@{6cKoEdB<=n zeIcSr5QS*g#G%(9pX+3g-27HJ`{^%=lGT>i>HsJobrnx4&&6&MLf@L8@(>=WDeCQ= zh|3d|JSRvQ$l+H)zIS*fb8~;{(dlOJ_$o;XkuZ%zd@|{GI9``EbJlb1Hi}x!F`gS6Oc>)w%3t8R$*aUU4JHh zb754eyYLM>=6PToPkzf;)Vp$8vt!~Q=b2mlurBZ2I$Xoow;;Hb7lh5n`>$a0lSXL{ zgZ*iId~hG@{H=UQ;TaSGujmz2cFwY`3xmlKCM*xk6bk(1`ApJR{U??-J-Qf&HTPS3 zR;QcTR%hDMApBk8Pxys-9Gqdvld)x8)i?Jx(>zzE&gUz~FoS|%FasQk3!beZ^9rM!c}5u`-cWllAT%L1!}*)HpHwwVx*9f63IO**k z5xKOgIJP_2J;0A%^vbt>&t?Ns;?6E=@2AI`rr%sKsP6rA7O76ZgP`xRC&)YPM$Zsu zj>kQq;4#cEBdi0 z!5oBDoaB=95`)=^T`Hfwfirj8{e8AVk_CuRdSqdfn}EoFMiQ-WU7PDlh9nmLj!ake zc)kgN_ozy5_9YeE#~;y(Kfiyk^)_z^IzuhM9bUm>{Z2f~+Lb_pUT=k{{pXTsC>bdPjt178M$lGl7j)~DQ2 z?K9TVtFJ)Qkh-x%@WokrdJF-v`1}ppH?-qp4iZOm7UDWM_}BFo9)hUzvc=!~x$dWA z%&aY*%I{-^B?nG(rkE0=?3=@#wf;ekAWlikaX1O%<0{434o{~#Kgk)`H{QV*U|`1Q zno=VR0k&AydT5uJ` zNQw#6s5-7ypXPL$8{b}+l=}Uj_nTys(A5u$Fuq35X8Ebi!3D%)QugR$ySVC?bN?&% zcjdu?L@>Su?}QUj$>!3h%)v4QWFnltb`jQ`7?j2Jj%eC`{OB2$ILPdXQPVV#w} z2x<0m0aVu&fkD~erta!l(-uFku?h+Bat+|K1XzcZuU(7&Ed1ta@(q`$hgXZh=nhk2*uD1i zLeX6?#q#Z^g#@?VB=nR12O6o|t@snqs2Nq67-Rx}J)RezQd)Q&hq>-asjAPs_M|l@ zsmgv(P8g>W)wwd$W{r*0u$v_MVE}~D(u((?rPYJG$ALQ61}|8Mr%mmv2DjgWYT^>0KmPW zgz-YGt4qC|*>WJF%B%UT!9#5h&{++q+v~OhuOK}QRlnn&lf+)f}D*yFkFKFW_mgidXEwKD{E8Z zjb1Kf!$V(RDB|=DtM^Cd(VtVl;PwK=_fHCwK?UD~5LjR+sTZiTBL#6k`pzMs>a#6i zh{D`S70JvO5ar#~y)HnVBQH3RSF(Zt()AJChzCC(RPZ$D43ZNn&L00z;+RN9!~mHb z?M(5}>!e+eU|_L&@rlq0*Qo}9-Y<%3P|`mFIxzhHX*wdE4& za0zoR$^qQeG$y4;vmg=$_VBzFQKxQ*UA#Y89;38|45RtAz5Wpe2}5+HqWT_~GiE^` zj{H+hz(3|B=6MwUhhy znyr^5Z2Y`qGd@N=zPk?wRH(=ukhv@@FN1aWEyZOz@1)&4^g<4SW=AHkYfqpWZDU7B zAbNq{acvN$G>Rpkee}ww%{~@MLjU=)G{dk0p1G5mFfkSlg*mPB>r%k%plB9m* zE{IEYBgB@EFh}GPCf5{?yt97qC$UDBRNm_ge%4iPjW4R8iCBtKpV;8R8XVbAx%AI8 zC&`28x%kja6c|KJHKBqzj7DV1WId;k2Vww&no+qg*%J`W8nZBT6%atcHwbG3kTH zBZOvgwu~3?N7sRwDN0Y7AhFYerIz<+k%}BHA?%IKKbPJJ8JPy0L+-+S>-zWasbJf2 z@Ge9WjoPV4hF_-o8lpf>8dAd6h>_xqjBrQc>3NE(L@5rgy-(1osXxB{V4PLNZK|P^ z%e^C(~JdpBzyu0zLmgWYa%a^$d z$Fz{(5*RZojMhzzgWKn=@WgH~NjKvAl|d6EF)sg#%i_@JTZ!H%>}-HM4Y88j3(#1W z1m|&An1b`EwxwVyO>#^=6#5Xh1^NAJK`d)9xcTh6AhJ6Tw39`Da+(@j0;->K?2K(% ztT|4)=*=`R>hBS&smbVIQ%()!ow5NOCvFaXA%8+}rf%$16zLZQM<&qaK-c4i!3rTQ zvv?K+9&~@GQyZ|#A(@iU=MGM3$>*Ugiyat;H08r*`|CZg+2Y~i;ywb+Gi3G}U?W-W z(7Y&R9OFT36@(W?nj)@f_g_O|3U<)I=*>N?fJ|%l{oA$o5`(=2+lnOl?~^hgJ3Jd9 z?$F1W!jpU+cGfZudJ|Cbm>cn0x0d5Y&VB>5zLhoGNmIfGSItXM#VW!J_kI#0dHlmp zIt_JAK^b@KvU5FfBPhHBH!CG26Z5rrQRTKU&PCz*ZZrH%tgYb#^}NOwbNb(*HpY}c zFSqS}O4UU$2CYxOMPF9QG?#9$hN8!KS)AO|WttsEbl72UO+9@pTX!}2v4WV;amISk zK?QBvahhbmokzOtrgw>S)DiXR36Gl-kkr&J*TKz&B4OnfLDEM=#g1N(CMMRfaXBSO z=1v#_=uiWuCNLoUh8{-&1%Rraou&j6oVXdu}77 zm^NRZkgAlH{iN2}yNdI&sj6IOXhe`vdyYB}D~y zzS6u-)3{*qRT0_w`y z7+}RbgParncX_yALlOU_+ej{H1dJPUfR}3;!>1mc_dj3{M>MB~a2ky2uOoS3PHbOX zA2J1#o~y8UVzLh8QEe?AV9X)AU*iq|udTnv{y7YcioUF{5F6GRdIRjZ;|XX~9B0t& zA>>iilDN9jwrM;TX93rdjZ-Y<4~gSc%>dYo`u3PF*0xS3j_zI(;&y%3jUw&)`O25F z`7H#>3p{$_PU#W`GR@W10o5!;TpRp6oKv;ot|&Am2YQ2k6jr&=Yk!~pR0|0LngxLP z7;~3kewrH9M27Q(?M#R$iFBMQCxIoHn>wZZgTU6qeZsJb6gX`f*rR5=1G;j1n1!V) zSD>AH`l&tNNZ7ALr!e++CO` zi?lN%n_`R1#3FnIw`_m{O!x`*#EbO0J6=NWKEIB5kP)=K46?@gH_GdPVo zqlhGWVkp&8*mO_Z`C!NU{9mT$*=R%A2$RXSGkd;@iayIk8lhkmlX)9B^Kn`nd>j~h zC=G(By|6J28q!UPx~N2!PUc7zZBQh!tRG)WNO_su{PH*ySdApKLb26paHOHs7bHHb z*>02ZD5UubIX`TLG8R9RUkl+#i-%F)shonO{M+7=Tqw{+750izXEmEU>B2KcXh@J4-ZcWnBT|dQYwR3JE@AP(_CNkHraHIx#nf@QezYaVrX#aLQ_2p7P_j z^6u znfc9!QRMkdApRP0)I6DVoxf}X+`6;nT05(=o54dGU;;NN`D*J<&&C1JFd{@rwxET; z5I;zF`K@i$5o5K7wsm2x6I_>m>A}zfepdMZcuXw8;l7xmPPpGJFgNyn>QiQ)5tdxB zhlbgS|CjR{Mzxy{LZ6*~ceRa#xqclh>d+(fx^yVhD?mVk_|HcYF{B6}pl8;+GO@NF zI3#Z|ZxK*~ggfT7UOOync#s2QOY)D2l|q?_p4ctS6}EB`K5q&z@#@Rr{`Cv!Ez?` z`Q00f?2+?4sM|Qol~6XR%BO8Ah!$mR1Q+IZ}!s6~Z zrdV6An@<=1a_(RaLV2SaP_GmWx*n0YFA-W^QlK%bf@cZnEXuC-W z;1CfFJ3pNN(2!CHC7HZn99AjKjYDC%x>HVWVy&Ac$qI%M!3}NC5Kw}0e=%;Pw0Ea| zE~cT*x}s0B0U)klhQMT0MNIqyZz2e-P2ZUD%B)%%Va@#bye-fs?TTF&$Ew9Z>?|=y^WA@yq&X%I2wU`%LaFaK<~nc%~mxff<@kLp9JXO63P>6 zTW=ceSHb_sU!56Oh3zd>D-n?W%9T$MyNza~i77#xTz3uTSD~yPlEsR5#vM!k15fN|>9@QYx*8T#V(_ z|NL;?e^db{Y><)Q;X34UIG-psz>=J|YoTyv{a!<;lDPhnxM&VcBb14*=p~=Z@B=KF z4Ecw~_k@Ygns`tnZ^NJBNxfxNf5t^7v*=&tVi6UA9WA#K7Jb&|G~f;zDf+@l9xE(J z@N>_Sg)|MpW4CGZB=z8Lv*boE84R(V)jY3N><71>I`M*ce+0HC_q$i&CeBPvasVc zOP3e_QW|Ut-* z`gAR~d&(e7|Lth*S#y!T6{Q&UzO9;fLU41FB zghM8b#9d4Ob-*jB82|iUGS(z;0Qk5h?D!~-n29?j z06dlTGq&6*o>;pv);1TfUZ(R))b7^m_tP~eV%yk29l)m2Go`$B)}AtIm=dBeNsv~P z;ISbqqW|VeC8sbd>>sH^rvB3-B2NlcI;coM90$8(O5gS(Y)wbzX;jbJwA|>JV^wWU z8QMv#tN?4ZIy3y!IyC1puSQq_GWGP?{(#R{kqgKW zup>%zMz=d0vrINock0m5-4Ag%*YgbWxn4--QFaVMcYSJSmbiX^$OHvenBbWHI&}<< zFp3~1_{v!D|-PuO1Wm6 zNW%TG~DbUcdX`BkH>I0<;*vKZaBqO zPu-bscCW7YCB+liU-JFT5D@zm$h?{BJQwm---@_vn#Z^l-A=YB35d^d?!+L!tfX0< z3nJy`3~V22Gy-!@4XSNrEcIKuMgo^PnRhc+rW=jn(|#Ow1Y}th*PLC8DfJWsJ*h&mKWS_CZ)N z%f#r(=i)4p-2n?2Y@&4Fb;GF|tIICEh3!s4F8Yku-NEE6xXuL@h$BZ=oTv1ZA^Y*D zP0n&23A_5%Fg7bF^#(D1_ieh<0Mz&-g$j}+1+vGyBCDRr*DmSFT1zd?U76n z)?BWlu;in9+0%*}-m3lsIRx_y72~`WB#W;XaFE9vPF>SgqDlBo-mDWEH*;Z2rjoHy z)Fo0xMmQFSi(je8A=;a%VGL=<>e)oHvKL}!rnX`kc>0*F__8G5jN^thy(ifPdidG6BE(4KF2CAgB%?8^zXnlm7Q#-C|JJFrVAl949KYNb1tcUlxe11{dj_Uj8K zDP-S$6lxSBSrqp9dHG#^#V_sxF(HVs_j>K1DLxT^A=*^&W1ft9Z4DRKcn`S#k9mfc zYZAB^#1{yk@GLzo^^Y6K`V`!V4leaqukSoN3kmyBZUUonGyN;1HbPv|Jww$W@|+GV zEd;n5yO=Mb$U=)lV-p78F!Vz+3PVQ57Mo3aJfOTC$mbJIOGu-F+y!~=xNrTlmIE*W z>PF+q6nsd`=-zS;JyW zN_c7E^_OVd0*2uqL#}I*f^P25<$qtwV#s9-3ujsk*Dd{O%NtynIC~a!m|%jFuC=uDtNhfPqv+ zAlZj>or$Q^w|{MC=9ljkkO4UJGC_ZJ5pXp#%j2h0CLI6lCcynUT{f^0_Pk)s(rOMI z-WAM(x^O_@5MDT2vmCCzO;)nalqdsHa8!iC(rmN>jy@pqrYJkc6E4#Hp9*ZUX!Ff! zHj?#jzk2n#oaQG`pHlS(lgFen31%+g+pov>cfOpdGjVDeuVf5ctnk8DEjqvaHjQ0h z@nnxj*V=xF2<|7hNudDIu05wK#Bfs(xJ#eS-t zpYN_72tkJ~K}3ux2~w>-3T!#=QQf-ARK5>Ost<&2H?8UFi9&r0WRr1z@1km9Rm{W|p&mypKZNwWjj&6`2#%QpxU+ z?;b(Z?~zO7nhRks6F7yNCd{#XH9t+teTJ3hO#&ub^=xTxE+#jGoRf1=+S0~M=4LR9 zh9zx>IWS&z^Yo3&8vP7P?M>4c1a@YNpX3+)NwUO}9HJ&JxPKnpa%m0(SlPw2ysaaC+MX%MQQUZv|TT?SM9kG+*VcH+9sD-5I?2VjbQ$`V(QE{YIMfs0S2 z_jpJ&=9J5>`bzg!()dDBLoRDJivn?9%m0cXBeGAF;$uivgtsW$Pt(NOI$(Wk|tdbWcA=UGDhCBfDzXrYN*DV`~Lobv#&w3uGF*i8n?GD`)REDTmZ|F=6D_ zl`0lZolUz&6+O%*2ruQ3xQu>%S@?asVzr!xn)Geuy9g6@6!Sf}2Loqr{{Eon`i!tn zNs2<^0_-Y$#AP`Ih#_g^;oEx)r{iVx{UcYZds!8qSXd}|yLdJd_o3~|AbOg_`;>{1 z_ygI7uIpgdmdv<`o;bzKGA&WE!WyN4)5TcZWs29UtD_3EF3R@T^=uYs6kqi>Tn-iVIeRM?irnVGUR zQ>y0;T`BkZ0U#M^fWRMCVYgZ&>D(3hNm{4avaOwv&pae7kxMg9Z<^>qmyEL!S!z;I zYN@909AE-ta8`u!NU3rQza2JB;hk&mC|er83byegFdlErRL?j=3%2s-t$AK4AADr*1?e8js-i*FNl`0u+h{c*v7_-6v-zQ^v^N!_ zwzUKr-V3TBoaxo@@palfp*DHPZ@yp@iM3^9Jz4)T^ZbZX1eGh!`KvE&JBc!^u;H0m z(vXlcb|7$LpOsi$2<$|{W?e?}RVuGXeM|~wB5ra@Z*Crvg~J>1*|8{ZrRHmA0l?szS2A!K=_qmP;Jqp8g~Phs~CS}wBGi1KbQ!A zP~Ty&e6XGPz2e|1kG$8`wefsY7we@9hKr?3_4I1w1$ijh9!D`re@x4PKSq_w7A+nY zJnGkpw}=A*Bf-x}*ifPY%WPWC=!r{@G|~J7qz{`)*H4?nz5(r~m zs*3gF2}H(GGNT$+d}eyMZ_UwGaFlH*sW#`T-tV=4zvsnvxqQ!sv43;L-+7l2^YNCQ?f34tx`AqG9$^45lnf3sOGGbWIj7#1P(FKl< zBdBV|Iivb!h@7SiS0LAc@>G0{%vl^|ya!#Y0KCCsbR@(IDmj&%-;s<_9Dz1*tB@Bmg(eizDb+qmJd4>pPkv#tQ z^yuRxB}u}GO1A6x#MHeIc^G?ZqK;ja>t!v@GAEBT8?Fn=t~o6S%QC+Sp=0;|Kc2oj zp6W0D-?+HAxVCFvTUK0Inb*oHBjeiZqL7TN?2(bZiO4D;*-^6hY}tEPWM*akj?ee| z{r%xD{&+v!d(QjydQL(|^&XYXM!*?gZcM;GDy@bcqt97`%Uy=^80dOe0%><1gLgBj zI2%9^)x*gB7Z>}_F2Nh2>_F)9vJg{RzhsJBY6ZZycPuTiIK&%QJFj;+Q|Hs$0I`DC z;6lKJ@9&(VMe!GaZvm2I$@i@?MczC<_YUyyqU+9^fSj>(l(HdGNyhi}9eTszst-}0 z6~}lY(7^rF_Qpy zl7G0=r&m#%APDf0CwadjP$N54OLHj`Gyscxxhk)@jzL{#Cvz8dBSlqKWTnvvqlEg` z_!BTf@n`=5AEc8gsYOAZ(;P+?rqLD}uedoZ&m2p#z>a`en{K=Vorp@eeYVf@m3tFd z1SU@+3Y=uN_kd8SG~p>GYZQbwz!*dnzucvW#Rn<}qp`=73MsmKALy8p3lOZ6)s#Tn z;xI-@%H%#N+wF(pQ{^C(NK!6SDUSzYq6b>`W?bcCl@?~FQl9JD;__wlK_C?jkO+n6 zJ%kdCgpQav)iFiqnOeuhlHaU!p4D*X7l!XG=Te&gY<*tb+8cRpQ~fihi}Rg6CzaZs z4a9wlF)zK1ET`^7&XN=3(oHB*Nr90`;S1kmg#*e*e=V8 zp-)oP3Wc(kI+?b)&7J)X|B6y9SBpP+)zyOoYq3>k9DV!Y@q&>#I9ufsWbk0OiQdWs zS)>Zy^d_N2M~=9&LnaLsKQgl9lr{94y19W|^oPW;h*E9t1{5MB-1k0oSG@KS6@2b) zU1V1K<@R6pWS1|m(ENI&qn^HWhZ#*~05oj`^BRF_LIE${cuXn4i)jMpi;_dsaPn`8 z>j}1)F^y9tF-MG+`9}6G1U(T53k1&kS<)}R9zop2sM`U-Q-yLQ7EV=%4b z^Twj^j~|L+W#S=9oIpBL9qA+_%PT%g9g@XTh}pcLfY$0NGHd*)6jZXGK}bmL6>Si^ zsp(KEx<7nE-Fd)rgsJV~xrxnMhd4y{D><95e75HyF~l&xLLrXRgzpjH)P5#6G+ z3ueogal2W_m+$q#ax2GHhw{v0@~V^mGXAFj+4u1SWrm1Am9E55@yYK|t-G{^9FMmT zY!q1iPbOo#E@F;@Rwb+#avfYj*ntgD-`xPJc`=_h!q|Jx+o8v#&1w(17Wwf;)<@Xy zkaoDNj~Au5`))wGrWond^mL&(ug| zA3hLa$J#$VXFF9?18?Q{r)xhyydhR>Obk?KV03*nS=Ihs*iD|wElaVTk;wjUB4TZa zLJ!;K4PM}cj*Ix!6ba{k?;d35DZkaPFRL*5Y)UW82oTN1vgSmDVZzAh8e9wfX$Q6? z{Ag$4J%77$RRkBqHRyiE$p^(UquL}s=fP3doK?y!4lc8*q~aoXv+VjDUb zTvn~CiI`;Ii4Q%|>Y>{Zn$FuEB^^O=wWLq8-hx{g{n0kkV2&(Ik?Z)?M*+HcB@|Sd zo#R>GFlA>C24LNW9B<^5QOK@R-?n=38GfH5x}#lO%gtgcefx4if0gln7MX3GtTJo% zbx(S`cS*8cO5-w@O+bWRgi_k5N5*SCc~G5M5v^*>rDDd{=6b7d$=tT99-i5f% zP4#=r3i7SUw-x#U*^6>O;IoWIm{mKoMKJTlt}z%9ki?jX-Ezj^4`0q`7c`@tuh0Fy{?j9GsU%QWBZ4% zPP@O%@GK+=Zfj;p+f55VXPfP|yUZ-zRi7a{K2Jqyd=x_|hnXpPl^Mb}oF6lGS6zMU z^`y(Y0ADL&JazqUM{S0@)Klhl;@=6wp&Q&4G1h^wh3f5RH)n#KTR+H;Cm+=9g)xaW zF0k9M817fIh6c}gdv#3b9w8_Mq04!4`2*rPSDhP4uP>Qv$GDo-zn0OCAvp< zaV~G^QjL<(hjF~~3&#GTQEas&feK&$}Dty*AZEwxk9E+kk+4Z@Zh__%()%2~d6>f4C=7W-D5Wj>Tq*rI@L|xwl`C z$I^~>7#Prw^}zo4Nc9|H?hxo#av$zI`26%DCz@O|%}5$Hwsw{H`2Z)Utnu=yosa~t z@KrQJbtwDuNwXi(jDw@|9M+Q0X;o;dUO~IaqoEIAlZsn%NBa|sII77!h3eFLf>4gT zp;rfpm&47SpM7?==ilu}kJh%-$oLE#H)M-#oXM5swaBw!R%=JJS)TrV21|oXn38%% zCrgVzpZt|TT7n7t+}DDz$9g_fXHZEYl_5_dCzpb-m=8)K=(rV7G0V{#O-_dKzwlM2 zK%4h4)>K(;O1$PtVbvy+U2isA?ebud`fntsxVH2pSx7{Lmc&$^oWI&KMFvLzYD5{iSx)<_j2)u*r#@u*5iypXXJbX$rICBvdL zb1zc0kfbjx5af$V2G3pTEPqlOPmU?{V-6U22OBN%nfL3(rmnwthFqEuILv?WnRUO@ zM5c3gCWEJuV&jfeh&SZv51{ric(@lcDs%BO;5SlrxBT)I+k6(h=q-H<^i0XcrrDVa z=Nj$pvVC6DzWNDj5c(@^$a+_SYD@o$=gTCS?BNW%4E~fUsXg`uI*@hcv_Ier?<>b? z`d#)<_&w%fj^djtBedDBZEz2K6Y`^J=bHy-to|T-N=zf!CY!gaAY%lIislGN`Z_qg ztQ=^b>1|2YFce=DcSzBJ9B*vNX8Ra<|79HOc;ASYLz+l9AJZKe&xAkmn_#dJ;C;ef zdQp!P8A97WUUA&GgDFSisbmL~CBBhq{pT+W$(mt%`m^A*$mTFEK4CFAS61W4?88g~ zN^Of)GkN0D%A4=g_9&<%-OmP}?t`Z88*A(au`PRfEug&2_ADaH^YG7%kB~xHij7u2 zEGHr{{-Qa+u|gl^a(*W<#b(8>g!?KAhl4lz<)X401pTfKZoSYQG@DoL5YepJ<}ZPj zS2%eJdP5u*)b0ZBF$7eEOE-aD!uy@deHlnaaaBc1UC8s85UofSN!MH#;F0d$N@)1Q zZrxvX@;Cct`3*b`_N0ef%*D@$SbdRWvS+$8F12^lw;K!D&f8e+uf<`%Jva`x8fIK? z1ak&;`foS!8twpVlMU*JDW_UQpt7?t;g&_s9rPAq&tr78b{F&|=vsaa>(`5J=h%*F zlwKxeC!rqfYB6BA5%GEDiM!|4a7k?NO74st=3jVz?&(``+dtp950QF`w?l1zt3F|6 zlfjGHnyMxuZ;w228BeM>E40;%eq4u#x{PsTo2^s;)(JoA?{{ViMceAoTeK4_mjvRf zNMgvWui3K1bp;ex+1PEG&}L-Sf`;ANHj`Q3oxzFJoU8m4n*%(L7=wXJ1r6`zE_wp5 zY#$y^@f3}{tF9NK?}?v}*4U1BwXwfai7RHigP^CIZoAs);pmo===WIDj+}e)m-)1w zJln>sH%vvWvnTBBJ_#lK4vuUWzIwG&dOXe)uJ@eR#B-j`8ei@zI@QQm6tVZ{iq0Lb z@>`qI-fflhOnq&d5@n~JUNq;MDc4#@b}xcm72^z4{n?Y0RrFYh2^zZla$3qYtFN%F&0>iMNjsK*;OSe4r~nB3qX_@2hl)4+&P`*PRN}R$r7G zxf!l< zeo|uXuR%{mFvU5D)0-#OuKd@renpQjXx_j!Drya&Td;wqBLNHhB|2AVW!b zn13TYG#%p@q42EH5^m~(hk;LgHk9k0gxWFdk|e6_V`S%xSC|Pm{`)sI3%R2>CwST5@a|o<5UtJBH$a= zn&+R}=HO!$DJRnPX7{Q#vuB=R+4L7oAy*)6;OR>_adFjG-{95?L~LCChDPS;7pwvI zXBC{Dhj6@t(oo}O!UkErZl~NAJu_vQX~1H_zU}${&-J3Q#Vk*$5*(w`Iq8qx`6fAz zn*k>&2;0!QPI$P!U8?4*&hmoJsoZT`zi}OHnX^+LJ^s@eW2O9H%rxsnt~xMLc0al) zIEI^qvz{tgvBC__o>4yz_E3&qiezyX1Q4DbO$L+IJ0xkO_9S+}?BT=9$LE*0LI#LgAmRHU99wHZ|Q)^RJb_JIj|f z+TLzTjWerBn7y<-a#val`x7S|KUh*8bDWAP1B&bx&0POnwaeWog+35B@z~bB=1^nl zrrKaTlw^;&ZKt8(J=I0ZHz^Rbc5ansRgM#dA|U!x5R@EkXB z%m#P7z|Q$U&N6VZTp)Lpat(9ckL+eVTRnph22H(UUhP-zt4NO#^%HxHQ7D`vUEAo2 z<-^|SRdygLr?piyBkx{n4tEu7G~8Qk=3YnJKEpVXao{D~m^f8A!lW(CZl*8d)byeY zYrR3g7gLy3(kVnfH=^_#`s8nX%aX71+XUw_zzRpYZ8TUxQG)1wkb)>N=PBmjv=Z_6 z&Q%3kKSF(#aYR75q;c{8v;dMP%)RUzBfR7*PvnkgJP|v#qO*rW>4fTl-pZAH5Ycz7jVrssS11d`#(uK^DnLM>OkDK$@W=`@) z6qbMTV=>}&uB+NAyc7kWyN|=SWSi8FnT35-Q1hyzo_5yaZ;$SDT=8`l)4-W1TQd-3rGGI}&nihCQy-l(7T1^ra&_Lk2x%Vh8NVlgicPJ+ zQ;yqtMsKNpL8lg3-x0fYcRwy3)%Oy#=^mM?4m^WtRj~NG{i>Oq#-)-WXqt=09D@yY1VW&@?F;>A0` zX)rVBQ0!Mi_o*)Z)BfDTe_=Z>0*!2sYq{GA#}b2MPh;cf5@LISF)-Kj+ct`_GO06F8%@0QFOCqC&+m zpp=Mn`z-T{*ShOs{h8Ss#LjCF{JriHd%?)*<=uhMjO6UFI5`4l6wuX4j695r0?M=RV;+a#Sc+k#CX^fyXPcl9m%+ zS)*IVTGXEo8}tm@c;-B`LwxQ6@}05=lh;B$q_{-GZ1bP~e)}VL;m(U=*l0kGd)_`& zq!C?QA%@YKJf-M@<821KDH&dLoeB9HUQ<=ydU^O>ZCH8;b7oTVUCEsCZ=!!<2*%k( z4P0(>){IA$@xOCqh#mdVbNy zSc5$XIF8A(xgzIu{fGVWYQ>_)X>v#J0?PS`E``hVg`?DzB|G!cxY^_Ejf|Yo+(Yhm z6)bf(T%y+2tN%#RIW{~*p>>HNK*MM@i%ZI+!Wb%~7o0d=(J1gHpW5O{?F2ZUVkB*u}&ab+NYb3j$W(MB+ z%{>k+u(zeHsCKkZ^sKf`jCBlsT&L4PD|pWVleg!cpJX=~>lL`PmH%3czpWm=`hl}2 zIg6Nz856$se4znQSUf>gxPm=OuxxSYkL{NFi@c4OpE9tcy*zcuYQnRRNe`qblG3J9 z-#i)+0s(l2tvz!Y9Tvuyfgyb(^C&v+{ERC;FGzaW^@Wx0e|D}nZ-P<&mk5^7l3e3p z<{@_VqpXUSljhu_I1G%S94EvyXo8GvU&yCzHuB!m-y?aGr4G>?vzwgk<3EHVU> zQe}*ATc&ba!A4flpae&N;$u99Gzt4~(B3XD#1=2H8fY$z-G4^DG|q%+AyA#<3?j%X zsozRcuA+FuddyGA9BZ_m#A>+^Z|3MY>D)2sjTw^dOquB?{7Kbu;eEbAli*AjjK~vhbAq`4J=rGwcYm+>m=zH^qh1O3mxyQZ=*DLineApO zrCSG@65ZLJO}I=hZJafBJ2H6(5c$${9=u#-CcgabY||H3cYd)dK=#}IExawe=Kj3Q$+}_c~%DAhXg=& z&8q2$Q2|s~CQ_D;AM#|xFJ_Dmv)$@f+@ zpQ7$vSZ4~WfD2Zn^Al5Aaqj7i!}aZVXv2TT;84rk^}TC>E4aI4&@gkC{j`gP4*&Xn|32I!5Imb!M^0q)k-G$X#YsMeqowGkL3%(VfcmTeNni7{rPFt*KoL zDY<+*!MXZA`n*v5sI|WVVIQ4s7DjgVvddiQp7+eEZ+_Zv3#!ZIzwrZ(Q&lY1XSU6% zCVcq2x+Eqfo|ely<5;Qb-NLb)d&O+nYZKc=?j zLFjl^d$4ydn`1>El5sQTV)VQxEPRMp31BtQGV_)u+$8ONcfLph0|)B5bc!&v@WzbX zI5*DX5Z6Jrv!D|4S#?_o^RlpJUk_oE0{Jh9qtFzUo@@jr#4gp^pwbH3!|*#81YqjO z+yd7_8hX-5>63&y5m9x1`V@DqC(IrRLu*I)AV_R=ld27>BgleAvCI#3l*DgZ=bwS0hlH!a(9?Io^#riNg?{8s zO5Bj4+VxJ2v~9T+ipl4{cI8x<)xZDm!KZmRSMe6gg7k$uxUT!21XL@Q*@d zCN|^}-N;5``R=2(9{(&hBYI|&wd3Fa(ila-6%y(tgJ2I_`K+i*xlVMu>tlbNZads< zA|4V5cPV-eg{N8fzdy2UC|%57d8z1j+m>kD+|~{#L_L;h*-jxuwV*eop+Wt5rL-;r!h1|qV!J_p9$ni2@Ok7VM_;&$tXDdZB z(Dp`aQ`i003LX8m1@zh@IrN&)lz8;+i+gPaQa{(<7zUinTAiF62#=4+I?jNmk_Pu9 zwu;AW3OMNdPR|vkIos-Yp6@AYFIx1RhaH3O%64|{OzZGgl*vqf*Ja;==+Ob&Y*Uj%@2>-p?pVE~3G&&{yA^z+NUbzB}oOeH?e}DNlAK zT%DTj#+;=vnYABqBviWX!QDBIsa0c)%M%djhxsq$+qQ$X3?pJ_$u9AZoyP*8#18ld z?`kNKd^ji=F5%e2qMDjfCmXdpNu;6P5GVM9mFZ9-)(3f_fd6;;V zxCA~iPJ;?%r7~ViAbYe3&LG&6uP9fLQu$44Nsm7LX;AwtZ6V>957YYWk`jr)5*pWW z+!Luxu?bcdn>jUY+2Ibh)Nq&-S<^E9$;S_GwWhf7h>r$$JRny~kiOgFS>rjS^~-L? zypZ8n^*m_JlSlA5r|G(1ruYsl{wGUOIXjf19v9+kiT6(9aM*9npN%60EIo(Cr77BY zJ6o% zMq?*|{dQW`3K|VVg^}*=DeY@HLLYgIOqD-JO^3JT+)Im(yJu|aXa7JEa(N$5k$B7f zy-gS`I{^`5)C|B@TIVPTa`~nm%gS@uf%)1gqXYCWB{F%$O1+BG^Wc@Ew3laVh)oju zsONYB1R@}AKY3t{i0)lXev2{s=vm&{tK82~%K zkJEN0<*+fK+D&+!a8dq?tsxa|Z0nk~Jz3oCR?P-55A#`P z^cM(1DGKP_#1ts;BOmMDrR*cXJ#UD{x0WTPTsAIuf%x+5p+V_qo^g^brN>|dg|2!X zxs-kGY@jl!pPdaE0%g=+^{lH!_ffJ`0Z^(|zp!J2jwrILD#k1*R&i8P1|zs^*^WLP32uVxigb8|48nyqAJ<45NazW3|H~XyL)$-ao17e|FGQiX9^NQ56h^ z%6&*kQ3PU?ua6W+EOmTNOM*r-U^$!Xjm_Pk{USm8CK)wdRs2*J z4vfhC01Rs{_`l74Z>lTmU1tjgPbF*iMvTiT#p@j3f3Nkpw@Q0*NGhXt3ESHtZxR@zlzA4G@= z>&d>8JjOc{;*|*_WtX#9KlrAo>R$kWjQ>~}19Gs)NKjK5ts!-%Io(%!qmTQs3Z->- zUVj#lz-v)>4g707&YbjAz zUI3>GYbC<}Zq!OB)1MK9qLw!$uhgRx^U3{)O$I!$3`Giz)QZtw3cW>hbJ9jdCf zE^AieW2z2S*5%f`bxq+ioh0QG??UfamAOEkJoyEVbYzGiUNRKv6R*h5Q(xL5^0jXa zB=B+wnOz>G0DPqKL1kco1g=q%HG8M2@*L4}gm_r?Y#bE?q9Ugy^&UcCLaHx#V0ci0 zFHEn3;_md2Gh0@jw4Eo@w<*|IUc6i<%q=?in6l3-iCiWs`t;m%D$Zw6=)faSZ6o=;9X^9+uL zfDV!8vH-qoZBG?KNc?x=2O9E!Z5v*Eu7WOh)@C1lvv&}58Lg`i;8bj*3ZrUfv#^sJ z6mMrF=MZ!rm0BlMEHNwZeycNxjlyX$jP7Sp(Vm~s7+RR~!)YOja4%)z_Bq1GoTaj4 z;Rt5(A-JEUJVpsJB&8F%v;9L`GeHz9$9VGtYBUwvNrKrRDhnv~PO8;AJPOW9LX=!L zBJ5Yn<9}!BL_Ydf9Ftw-^6}Sep6`(Y_teJ6fsb;|9Diu-9g+~i<>E~;lc5u7uY*%f z*Ebmb@K4i5UWa+=4iw(Kfh7x*zr6Qvk!gcgzf2$~T#;o0XZ3E4v+e{q#+Kapk3i9Q z8P=-)aCu|d99VEA$7sqHKz^af?}d}!n9ig%f_#?Z$2B-+q=PWhCR*lqAZKe7Zi$fW z5$_ULw#uGq8dv~(P2a~fuZ<1!O^AGzLWfw0r?Nb+yq!X}*YR{x~23y}f#*(;iyq_afv9C$6)i@1}6-ya-kUlgOt=V!oZua)LmIZMs z61LbxFV>I46bZYe+2mb%x!97(kAIit8K8RqyIXXpp&~@Jg`y{>vyEBbw*B_}qu`Qf zw@!*MpH>{zZJU~1qZHUUAy{32KIOOz=E-bf1-5vSEbd3#edU5*Ac5jaQk8My8e4sGkNH4 z?uuNSBe2dG-kt~INgB}xnwoA#)YeOx!IfI0{x5r)kwW?9f|fdO?&dg9F?Wj}IZqDq z7gLHQTrpgEFx%~rxT+MqtLU%V8BJY_mq>{T7Z-CWc%M__lt@q4l@CVBb$d~LBWr{3 zk(%U@*9xQp5_^ERqQ^DpB%ZIrH8}@^kQg?%MI>#mjghQb9n1ziZ3Da-PXM|P zft!R&sV`=WhgCMJbqw9^{IjGUS8^hpZdARlxz_i?){vQ$Nm1yK&zJu;hj}R4 zODZX~Bfm4?@n;AjGPeF`INBroA~)j|rRDh+rk(RzYD~J1lg}&g9({89p(jaq^U0@-;3S>M&53Fem zU-~n!F915hi!Ztn{-D4J45?jMRVX0P<~LBO^D9j58dcbMWv{$bh6&uRHtjz^!YW>v z#n7G)e>6st7{c@=Ldxu;OOCt$&wpW3g!zyl%lzi>{P5EYP|tGTFm;ceFS;I%#oTrW zq&R8WaHXh@jcZ5bhx#gDt;S*${G)cx;$nRy)&kg|q3K}Gjjwp##Fh;SAL8u{>-3ti zaD1-xn}bu%sN6`1^S5KIGQ2J>gwX+?EpRK4UAvO=-)5@$p3stvH*r0<{HUPWElXmY zi{GXJ66^SH)A5}(*>eiUCAzpKSc|2C|Lc5~bR41I$N7ooTG+t7XAWSpfCpGu32YF3 z)xDDM$PefwldMR8Cl?1JU7G2JT-}@qzv-Z8WkS((c?|Xo?nhsu&dkwUAr~w?OZh}S zO4jA#BP_=urZ$v|%qCRQ5r2>=!8ZN|7p9%9xVRaK+&pG9$nGlFmG1!LP-!oa*D^QO z>r*Kh8~Bf6)rHW6VxW!H2Tc)SSGNe~&I(YpiVn5#1r`iqa| zY!ve7fB>+W6u{j8+sI}?*`{=ep1DB=@wGxna}$p9?qzB=Oa>;fadHyYrQDIfQe{2Y z1>Z;aHLeNLqdpzE!yg!0Dw*yUebKlJ!*v6R`~C)OaJ4SByD)$DcP{-^0>=G3D;xd$ zLJ}D<$6Z?UZ?bJj{p{0q%|yQIY4Ci4=B!;0321U6X19>32W0vim0Mpoe|}@P#?Q@S zu3FM+gWzWBA*jEPAr57JZ|o&tpoSY<j%XJN*my5Mz`JbK1VudYsru5{Ocoz(SQy@86|#qdWoG zX7>>}{mY%Xci+iU_C14brV5}`k=tkZ9)w(M5-;B^Y4`TCa<@_a$k#-6qJ-0OfR`^| z>7@%<4YZhY0hNvKA;`tBUO4XC`-wvw-N=tPk~F9RJocI8Km;u9S760jY!r@)NM3wa zicPE!E6E({_nFHrYS}Ju|4K-oZ3La~-C+;GmDz4wf!G#+?{kQhIy{y3jV4Oq?NtIX zN7nS$f6HEwCd#hgX6#^?7FVW$p(IZt7j8E1Dy`)F71}M0VfAvzazEu;xE_ z(gVsB&J9jQP+K?NG>YKY>>E&_HhW^r!Dc*yJAt%;>EXYAO-(9FVp<$+x(= zNguL!{m@g@*iy`9Z#3IKM8b0N&MQ{5O=kqHzzrd0F3RHl&dq5`%y3u#DQQZ}9-q~~T#6Rx(S3-i0>?U&2 z(DtU-EsPaLomF1XP_y7d^EeomB%OK$9HftIUkaLJ>^-XPrc0h032-^!{&$}ri|Kk! zDLObFz-FN23k9PfNG~`l!#;jnZ zHhaPA_uwDD-w7vor_pr!G>HG?*GMYtIUW)lr4gD>Zw$8mF$Z~K6IhZfU~X3GY1Dw7 zq%Fs$CL%k>(_`>g?1_y~E(MikRL(>ax4R^1veIE@w!FL)bLi^u5DGkIOjX$pJYhU6 zE{7Nnd4du{HVN@iTN*4!b~!uAhIk%L%eqlt|0+b5##r}xE#2CWvwxfK?ep^x1T-|2+VM?&)hnS7ccBb_znkX52!8#`{jsBwYO~Y0LLT}z-aY7>eYYn* ziB>jj(AV|jFP_wA9n&D)sBBg;K*x<7SMf-m=exj04(yW#I6A3{qQ|!d+h6+O6bFc_ zwy7?HNmZO_68vWHY#JO}XN?1-qQh&D>S7Ne^pul0DTFORrpnE~y%8EchY`KbC*v<` z(F6#L8uJ@rG(q>%w9UXlEO}pbv|VE{9>i%fAQ7xCmy!3tzc^q)OCIq6ct%05#f6~2Niuu-6f8E$de2=A zQJC*qbq|hc0OR8Ry#G$N)3}9?h1hm!#Y;K=Bbpvtp}zMdZ_`^$7hdGFOIEbz-pP4H zfAvvk_8`#{pZkuu$>yZQNimCUL4Vct=1^=23x*fUjw^(H2?l2CwSp+tl+E|8^U>aWxhhGd3+xWWH8%JH z2F*HelWgW-E7l%B(n}il*gamV{K=-yL~knjRpTEgX;q{!p77F)WiW^jrHJ7O>k3}ZK zsGN9IX2Wby#9_=1B_@P0s1^<|1438FRTPqmkCUNfiuLUp2wa+?x_}>nS!t3TI&E0_4;5< z57S`rCvdXsNSn$9Rj?auO) zZ-x5rHvdtrt{sY)eY_qtvt_HslHIah3UlIdI&7H|)E8D*y968F=qhA8e4ONN?dzBESz_?H^7iNB`5%2IIv-b~ zxsZDc#51m+9?>4k;&l-3COS(k>fHWSY_JECSo>*>%_)y}Qv`ZvzqnRJ5u7=qh_E3; ziR?(T*dnEPM!`_wabGnq?iBP(m&V#XSE1w ztI_lORsg`~?(C5!T{G_C?h<%daz0{p<8YF;gtKwbVlxA%`I>IR&$Cu0aR|cjmR*v1 z+Phv7?ar@EQD%6FRo*OxV<$^}%61k=4-`r`JFm-%zkTxA;YU26l*Ny72~2b!iLrWZ z-e2X8Vpy3WvU3iyZu&&G^e-Z9peH!3DWd)RJ(*!FPxX3icdpmCiP~SG0q8zgr^XN2 zRR8_!T|l)_qEC&+9{OKwry*A~ObaPAYVJJb^_@WeBf_bP!X#KVTPL!+m%8DKD0xyo z+y%#2VxpEcRSr-1*X^9cdq+aX3!HwDAQ!I(CnTC*NephY0x9Q>d2tqpkPq-(Y%xvw z^U&fyknMl=VOpSnW^%NwJSn+j4f29-=vOd3?nMMJ}kp#hW zx7#qc5uFC*$Zsik$*6vJQ=t8v-BaPTFMu1>cS)wI9|7;@pd(q5?t#9gzRm$L_nxwU zTb+#S1B@O8ZwhqxGoX!6-7@pJiBQ(S(t=^xMnn0o{c zI7ay%bGD?8V8j$Bbv`VlRpyxo@mAAlL@zV!8Ag}Ud>crIeVW%1DBk|@*uI<23tN~1 z#^nAqM>9SY95U)qWopkU;ccFoYWuO&-mLbm9~xgM&~jk;qV21PY&ANam-1Ctp$QcF z`Y^2PB{$G=io>-_Q$!hsYkHV z&8TovErjY(p@GUv2J*XA%hRCQ!JXgj%kZLRhM8n)$QcutUUcguh=hO4{A_%7VarEq zhG7My5bCcfs&ZOPA4|(&(xs*uh z^{ZA$a)`hLVnC+#d|#^_b&vOMWZ=JFZ_440S$4vC zq4FyqYud%7)aSJOu=d`yiv^7R;@0t3iJz>))#IPSAEn^3cJLpQPmpdzgvg_Ki^6tp zZ=Ak#Z0E^wsTmg<;Gt8I`uB)ztEP z7S{>IlxnzFo{8tNXi&M}u_^v5@ta>{fId~bA^RLB$FkX2B#dA#?%VTwe(Xu4i17uS z^%spBdHz)RI8h7ky)2ne?}+rWi=;`@9jL%iL_1`XsSgc^eCa`bDUV_Cm+V$5{5vWD z9kpG@NIVDxp93x4PN3&TNb^j4g3rUO)2{DQ5FPby?5}#lf^iaNZqaovKy&1n_+vQB z11rhxE9J(~GxxK! z-aU>s-F5ASe~PZnW^#mW%i>(&x8#V#Zj$mt5EA?|TEK-c|NX>bH*~R;6FG6%8A57e zn=MB3Ex<|$&#yB0M(NF=UmfeFm(3hj*)}WD9H0Mw(+U$Q6hF5)5r5YdhCDGGmDy>o z`*NRGUKiF%BhTp!IW|=!Jb;XXgssseBuY-UX3PM~t5v{J zjNI4+Hk;xi0WLg=QcZBx6y@D*z;W*(? z7txS3X_v{WwxzWkm{t+cT;RQ#p}aEh?g#Hp+3pLuho~)pHN`8*m?Xbj>WefWWB=RB z7EFVZRXp#;R4pQp!v#;t_N5_)^PTQ=&JA)3XR0(HnXnFSz#Lv#RQmQ3M2xxiHQOBh zE`P5HTzKOgBlq*VxhD9E9dpEA?93sx&2C0K>AUMLbnhs((d%K88^pyMQhxasbG_BL zx`q7T@IUAu|Npr9>aZx=?Q0lE84z)3=?(#jAw-Z4kx-B>0U1zArBNCwmF^NyLg_|A zLO~i7kOn~sr4f~mZ_lgmIluG$=XJ?N%yU2cUVH7e)~+Q8}7iqZ^ky6wSXdH6cAw`(GQoUrJ*p0r*QU@%4^#MGE6A7wH25=H)@8wQ^wE#iiX zgG151>&Zy7w!9`y?5KFQX23Jk=jesv9oorDmi+4i3za<%MY~AtrUvGNfnMQc>RJ5? zW!V79^)vaxBxMJn{*O`ExL<@H+g6eMW3v1Q?1w(a`)SKN4nmQnOe@2%9l~LU9#2z8 zrUT*~CFWT#au4z()ACwQr4uyw8}n5(CuvDUu!!|^ zJtm%jB%R$4zDKdNs!^GSX~w}-li)f{=6NzhwjP(gl@U)&_l@sPvKLG9PZAax`$(xR z!N)G4_-FPtBc@l(n$nKF>wNcJgNE$7l@8O3)$1COL#saDBA&4;zM=TK;+M!+F(U)AeuhH{81rhMzqwlU+uRx7J<=Lib+B zTN>aSk}b~+{zcr24l{)l(jz_G@!@e1#hR$7OXz?EK=fBGYh(DHo~0MNd#b4PCTV3z zR>!GzrQhjFn7(pxMM9m04$SFA;bKFAXJ+ZkL@!Nrg3o+ncg!Aahy2{aA$I)hdXG6W zum-dXyFK+u#9oeJc*BAiTWJLIp>!DyzW+e)9lBxgW!_EuVP(u|gW)@579^Kxpdv%|{ zmBwKEes>BQ9b_cc%aCzfAyQdN%5S7pTx^;``}q!6*x=?(NI5LL;?qe_Q+V4Ca}f^;URoV-xAE z?kG`WQCmCv2oXTEs+4IL-7otbV&6$Fy~@h>I^!Q;7q5Yhc<&gI)CrRQGh-?Cty;>- z(6-cfT@Jm(6k&@4!Be)*Pdz9gvt9KK% z;l=ut0>%TI67D&p#-Cj;7d*H|!g#rcqTb+#H>({I!7$uWliq9enSck1gnCCQcF)E8 zJ~r^jiIa=Ykk(v)o!~n~vjuqZRg7+>CbcQ&+eF7b9aZcoV4UKvQ_>%(-K7^Yw#8?i zyVG0-t`0!<%qRW335Z54$>S1o{K}O)cEeto-~tuyI%B=+0X2ZFWwgHs>?ME(L1Z-68CS*Ao~UFmuYi2v@`jm zx8N`sZ=ZA}enz-_?o(;g%JFFVf$Q-!<7|SQSK8TmX8TqlR1oU%EAVPFN9D=jm|8(a zEjx&%N`OU&#Y2?HoFDo%o+2whNVy(mkoZo+iO8sHAH67_iGJ%{2uno+WG-ZE0X?JF zDXpwN^UVFT4T_CDz4XvBGR8-!4^r@R+vfJ&`Nlf8Xq<|87bLMAQ9O!ns2aJWx0yl} zx2ZWdu1_+0=8i%a!FZ0K!{EhM)_T+N5s!RJ8t?G8mFML$rx%02QHYnihl`fD`r>hyZ0#t4Utd@84+i}n_7xQvk zs7RNv71i%C%bH|z^suSQsTZZNqJ!~1$Zeh6P^uT2Yt=*#J`(h-I~Qi(Z@SxUdub!i z5#waeOSAEV=)oE}M~n4St2{>P#7R{zVxc3)?r)ZFRzlu2gj!yla)~9SJD-h{^>nJ{ zN&YrA{EW3s{#5dSuOp6_?sRS!pCTS_tfzieF6K&pR)GC`#o4@<>6p`;;CLNHW$Hv^ z$>RE!$ATC>av4N32+fo5 zMWR1k!NY#Mge5;=&w}kqmy-M?GCRYL&XE2#u_+gv^C9hQ9R4Gf!AUi26La^8Ygaz? z7v6Xw`PnPhf-w7SEo~gla63bY@b+aA!+`r=`BAlz_uZbq`UP+zSR%{j>y-w@PkX;_ja4x1kg>{BiHn#&jL}Ol*Tx?M<^y^S_s=-!RRNBVcS4(Im*MA)1_{#>`f|B*1)8O-~ZrKig4XT`1Brg~@Dh5aa@F|W*<9Zg;#uYzRUZ_l0!+Tsq# za|qe}4K^b#D47~Y^zZhTZVPA_N9+5E_JF6F?X2YfN`*p@Wzu#H-4eRxCKw$mrv3WBNrlrC6#g(58ILLx;%K3w*n48%Lze3?{o}JX?_~rs zx@@bQD&dFJVETLubsQlL)p3BN880V|8yH-~Hb_H*%}*Y;30Q@%qa&L$v{kxAb}**X zIFYLjMNFBf*_(MtTgW4$?@Z$%m-zzvPtzd5?*z`Q#ovp014`Ad1ka!AD0RD_FeB>o zjr*xW@bCSu%R`MLgU>8|+CvigQ6?3^t#aiqUCfG#$_8P6Wv1>^RW1@Qr8;>Lp-AS> zfl9loo8yEwbPgg$~5w*IX&To(iDF znXxq~@fAA_B`sTm&j^<}TePJkm<~F;R+=6)p5{?#Sd1uht@UjgZx#4p^xkLZVj26v z#8K0QmTfttZsN)kx#^=V)+Y}Ri5VnB5<-22_Fp+9o<$_@Sx)i|gvGdCqEUL(>H)M5+&2IAc}J*wy^LFVX!TRYZoKm^kcUF1!7;D^#Gn zbyB=dJz}u@i7Y*GV}15pdyQGBnXWd{1R2^S_bR4=@MxNr9xvUQ-J%@vVOR0)*yfOv z%7o+QcR#&>d+&%IIHo}8!(;d7%L|7z`s!H_(5L*SDXHyE^VIe5B{gVzhE@6F)*BNq z&}_Y=ys;g7vb^xBck<-Db^}4Us;SiD4N=MxyuV#h5)7}Tv_nViA!#VU#YxKAAOKJ+Y7FCcS=u3bDKTsL5g z#d`Degl$35jgU<#Z!Q&*P5(m!$~WQ;?54qI2s(nrKim&93ZWs<>mW9^FH;)OSkPg* zCJ}dHk(Z8-d#a54c?tGsK82M;Upq`-SRw3Pq?Jr8wl;n8pKZbm7d@rMnu41B&S2J* z5DSjCoJ}i!y#L+Opn%6cB7L}Uv*Z1%4ClVX$Ft{%#lNLGR43bHeU!_o4a=!x>Tbge zY!^?~$(Pg{ay+mPluK$0P+1!yjdfyhCc_%E^}S(0Trse|&cqaWbrk(8Ts_1@TWljd zT&_I( zwkAiJ>i1hbfxqU`W6!HV4)!VTCbCQj(u4{H7IvH~%0*$H;vJa>lDgbXybw^!)Lu_` zP{g9_&wWzvPAx7NW3glBa>l4HZ@To|0`cJb!rz!a(l zw@oWX)zTH>?VclhRRw&a=`|P~yC@JJGMMqpOAMo%7e`9Wu-=XxrJ*31jkeSh&ug7C{%^%G`KCp;absF5Aw*b^tSFj?OQ zf*FmaNIT-iW!-)Y{wVQcQKhOnE4|aK!!#lgThgc_-+*=zj~phNpDjeLxDXGW##cPg z>}6qrRZ9;EWzDCg#^0(inZD}inN^f1i5T0lG$CbcyMAh<)LZI67=3GOyQdX5wxgCi zNN>9GByuPDcKTJ<5vGzue{uYg+lGDcOasknZgq=E-utvm#9C4}|Km}4V>hmN-iDH=U}hKdn)xHUIB3fwdc zJcV#=kunUf8}R)>H0CkxUS7D^hS|N=OPo4-QY()#Iwz=i=~l%oFXi+N+7a+(*ieXT zI&>;}*TuDEdgt*W-5`4?_J>MmX}s%ASCPL!YyOd6FY!dZ`@KuEVZvQ6XU7Kvm@~1X z0nH{+$}y}h1BOVo4)o~B)+HpOvtlnjM?`mgWr+)&8dMF7>t%7{2r3g`5E~!`n{JAlT7! zYen-rvwhSB{=04%5Q2o)7Ecma_?&P=xH&Z>!p%MR%&^W?&ZIKH4b)0gKXv$}9$h~5 z7>L#PQkGF)Ce?G0MChc%r=fb%K#UyBGKKF@Qc;vzY0Y^nFL;c=?WNY_^_BalPPs8O z1Nr9E3Sw^)wVv@(V)(wL_&G@m1dI~A{UBP*w#8DENx~Y^6EvIeN$^FM>T+uD2`%M- zsuzLND2xYCn%cV0&6|3~CUo-l2Gj&Z$7qXi>Y{f?N=ec93;6}bs)t_7MXz(qxoX;L zkm763!$QfS{n_;@5Jf`rd|+>?p|2*`rKGyD@4B?7rFUuNTcd^tKRx6w@2ZFv+vVA--t8&Q}-qkEQ!fE)dg>%4yuAbitS776t2}R^Z)z}v(&loS&gSO{thx z3x&#g36$^_bFG+%m@$Z68%unOWVDf?Q_RT-<>2ebwNWwI!)nX?=J;)R{GV!f_V$^q_6i?tE>7OV?rz4jE*G;++#Av~ zvY#?I`dFhC|3IPIn^i18RGyxV*9%62vlP9?G@!vC82{~S!cTYo_-4Xg)9bmDWeSDL zBEt53Njw#r%fm%Mc*JqhL(p_1v{4E4V)jXd>TvBo0rd-0b`?lQ%02{Em;BWNnv(iO ziCOoYt6j`Zohz*9%P$uEUZa4%Kg2ZlOIyjlLB|U@D*Fr=G_C$1FO~bJk~`=`ZL#Go z?JNaUM7p7+QSvPK;7e{rU+a+80{(@Cxd~(vK})LfZm6$U_be!=xey|~~v!>F14aH|tqX`L4`r6Sk7S8Pz zbt8T@2XOIN`+; zi3hO8Ro(g|qA^wwEVKT%zAV*1>X*jH3&Ho#%6+sQI)NWBbtRnE>QwjsE42Um&~M&EaYTv#O0$O}sIuJ6tCM0VDr^v$Qmb)dibnpdUEkI3-ae9ZFNB9xoaZPdd5 z(JCxBA}y;#>SiR_9*4__ht}8<7H*XobACUUcux26cLgsc;>DcAn;6fl!=a{u8(jou zd$86NyLF)y;?O!^YM}r4{`aJOe8ftkH|YO?urB8abT4+?IzZ2NSEF2M;4qPZf|w0rn7iP)2n%}NNJBy8QW`Z2-!Y*BAbh1o*|4x zTHf>XxLdXKNR|RW!GIPil$^mrrD<>cYp}#=&Tw`<`be_7XjZ?2P8iqlIG5j=7jWu6 zyxzrdz3~FC&!MhfQGMS!B2N@MC2EI#WH!>lvi~~n<=r)Iy2ARK*QUU2c5S1`^?t2& z@Ra!%Oy1${cDens2DWQ;q8$O;7RbkYN9zlu^%&dmp-RFoQN=@FYV2orfzi&c+u- zNSK?}p69KP%%?*jugQ+S1L5OTpU>v(d#12ZIFPaJVuQ4})r}BtROn=Yi`9@NZ8cc) z444-TDBD=h>bX|!uYFx=h`XXbq4V<0^zqSa6PJFayp|S}7eodN21?n5J~M&FY4e-R z@mT0%^k|3y$?xc?2x8Q5$JYQ9s~p+gC^H;og6tPeFP$Moa+z#`7ttZ%ocoH;@U9>$ zKmJ|pksR}T+T=BG@bsu(H`AN<#;ja;JsDFbPPomFKV%@(Sqcu7#EYLj6l&Zi&8;!J zvSB1dRFG*?&C)q;-x7u&oq(HIA)iD3=vH1&F;>$MC?MwV@|oNt(f6=}GbyEQu5O@x zJg56G^^y$;0XRdSE#HL%LEU^5YYVHoLK_7_uLuH*`mnwnk3y;-oBQ0R1lD%s-5N)m zg5Nf7diQ>j&6|VnH2!pG)#&~+yNvy(Lc2(pbONMJopQ#Q<=c*CNw1v^o+fgyytmbc zQ`HYHy#i~HvI(B&ul_3|U4_pQm8%9~WScoYHtny~D=S{b`M_~mS8sxMHS$v7VMr-} z!-wj6QIQiV$P#HY;--J9yJh229iz;P&Y>>I3sxXUVfm5nVxU?uEchweDE|MXA$!KU z+)ejus4F-Y+IvQBdjHn_a%|f2lKA|%&x((((7xTo&6@Ajm-c`Qiax6EkdZdvyysi? zf}$>dM7rnufOyI8E4tE4EqP9ht7p5~ovA|$Uq^(-&cEq$Y${H09Wm1ncDpNZ`(Rqm za9h8#)KG!i!yH@#zB|u|>ovTSos2JA7(xy4T#eIpu-B{@n}qFAbY2>po5xH5Es6|p=&zkNuA zBx*exdB~X7sP5+GBh1HbotC}v+X2G-L`O)mR%>VN(4_)3GXb(S#cwuMS(fwd#3qOw zK3+!^qcvEb*Bah@)KU6LVaup|wC+@N+>al)MBR93lKT(TsSL}N4NtSRY)WQZ#QkKc z+q13++K}3j_jvDNy}wPlx?a}KNMkCEb{Fm?OVT=FB+iDMT&DVpxy6Mm;regB0Jm7u zNt~05V)uuUPONO%n`Hn*4>Dv{y}zKDEt%dPoFim6SkLEpiiagq3vdmJI^ZjnE2_he z!Y?s}^3OZ}#|i{01)v<6Q|o(s`g~5%pQ!3mn)&)vAR+PQ!@MrMF#$ObM^Is0{ArCb zPJH40`hE_*`_Yw6&8BBL+xy+~Q{ZCj9eI%Qv)8?RBzdGeApV#*@g?6d^ZQx^}RItc;g>cqpYh^vo!=4)h!2R^5Fz-<~>P5^7kck zN$xd>QTPui<4%`Nq@w3bI9>dRC=a8`I~I+s1us)`w4!eyF-m^Db^$T~JI_1qo2O3BtvD@TsHFUd(vg;?EoxJ z0`2dw^x#UmbKfOI9$y#tAS{OBVIKi1@%K*lVrCs_KC>_;Ii?7#U+0BEH4z&>_TdKI z@V3M2DZS6Yg7M&zvHEni$E`X<)K6IvN0YZ+`;g70>Rw{rQ*k6^Ovr) z3k?bEEt!1OY&X{totpsyLX5X!DM2*4kHGoxLiH#sSpePL8Ws-ruT+x|zcu%3@cKnF z7IVyD zidBU_j%K`NISph^+iNaEWSD5Ow=(;PcG1;;?_o`FY&PGv8L^JKML>Km(@$3rQRpBv z++ipThjM#uZsz9dn0Q;xmOx zhHBtGH-HOIi>C2spX7X!WklY}+okUyp490X%hbBwwz@%R!%DK5`&gC7N|Nmq|=0ojZNs5vHobrr$g_3&z(OXn(!tXKzw`((ckf&VfL zdQ|dli(b;Q%F6Bmf`r$UOmcfi879lN0X-nMPUs?9bdL>7MY5sKT^G!=gHj8|sDV>h zeH9-wpIxhXG1$X?7ZnwScpyglea$#8+G24Uw)OJDs_()9T@(}2Yi^JyoY)x9o3oU> zh*hKz`J=eYuw^86h%%tDH;@)Kb8a317s~^?U7L3A3)JeB+?28zDSqa%HaUj2{vbXZ z_UVHb)_^GbeS){h-Zxq-F`};aGfQiYVyp{{;8_MSa$lpEWgzFN3bRt@Ajf|M9b8~f z*)ZH2o$-1pRwa#lwhusds{Rdq$^Uz{o)px(N)F_;G;u8tWhjI&JrSWv;9HGCL!L~^ z5~KVwjO4w{-C3$PBdXSa!aDZk6-?BXGWG>oKuJ;XR7zC$qlCQ!3NQF=Gy}-x>G34} zV%~_xf~y0Q{Mq}_FG3d4E)?22U5=s3cIb&W&x6;vrI$VXgEY4oQGJ5zZoN|97MD@ z&X(Grvtjt~-kbHSwTu1wc_Etf%_Ljm!U|Lg+n9 z^piq410JbHjk+sII2l$$u3#-&Da0qiroe~|ci1pc{`M4IHbyg=Bj4auE&dH=??=q| zo%m#hqI+GRPblK;^@N07J8*sM^?s?TI+X?yrAsJ2(^9LH{-^I=T?iGj`o5tD-3@rsvhSNGYqq%80gbC^R_Claez?ea!@4ZV5+0NlhrMw zJo04tZLB~Ahymr@;6=&17f@Y?!hRIxQ||q0p_!Uaw?0MqWLEc zjAlS_H%aY%&&qWKUilk6MS*T2s`qCX*~zCvOb)M|&?+g!r!nX@wAq)#$8raOD|1b$ z%=~h0w@R31rH()rpVWgHej*nPT&4DW8{It-Li{AlKpI1RmLAOQ`)6M8*yV}`dr-0x zylEPwabW2xk16C43a{;kPJsiICn^llV3d>>x?J%BsW!RhzB;bk;lqFhqajAwh*gxv zBC8Pg72tHk?TYG8&m+FzO3$+pEB74P@4nxjxrZfr4l(Mx9 z?XOb)Yonl`@+V=CNGfF4!ap6f8eOfY`lr+;4kY(CawF{6GO-2?JQV(2O6CxEA)IW# zkvb!zrHw3CnyHzMh$STFO!5ncEBE4r?Jx2F3Pd`{{6UeZ9DJ7PZiEk{6U$f7S{pVn z>b*lnSwuTW$hG;4yuyJ!SzzzBXx_Wph4U3|(N<5_(nRh804gSLy=cmo`4G2srP0## zX$MhT!%Q`KU?*-2MrA=c5Z7DXBZNBhkxKb8@tCbZ?Hn1~jJ%#U@jjGIm;jav6#{x!J@}M ztrx2TpQ4dn^}Vg>FoIhdqD$aNI3_!tZ?81w1NZJU}Uj>=qMeoaqndB3)#P@4Ipv8fY_7I%ov9 zTgBtC95w1%0E|3$uo7|X=yQ^8_Ns~@c*(|hYdQXEi#kpq0Dhl%Wt79J$%;bnTve`v zkkCnFI^1bvtoOe@=IR2}rjfukb-IH}>Hkm-jQEM@Joc~^N4|D8&)-Y&WYrdCI?%up zK?8ewj0|x{g6+{mfOLbDu>eo6e15oGq*E*Hy{7_uJ$jo!kEmMI9Mg; z!5IB?N@VQD@z0FobBGc(6pVRZL2J%gncj4`dM}vR)&W;*KLk1e>@Kndql{8)GNlY2 z%_8h+7MP*4{?#6SSPNc|g0$4pN93d#GjHHU?uJjmgdy0f~*z}s_wVHDMIs(eDG-k8q z85}y?d-&L1WdDlcaAmRj8l6BrAjjASx2}9KMBe>!d1Y;gG`Y|Cyd#w7+t}?4)3HZG z{qZLe+yY-+ppp7taEOP$1$1K~c*)gp8>a3DN@Sa${rK>05NsbG`*Gp60B~y{srXIq zV6NO+F06>?%+Jh)yEWb)ukj6&&(7P>(7a=y+il8}9lOrIOe$1wr*{q`lz?25|9V(h zWw+!~8_o_y!EDoBpt9-~^L^-@Xobiya&?C1pY~HbRFvbKnT}W71~o2rLcTzJwK#q# zJX`}Fa-P;9u&OG-Vm|HpeE=doXsy}37n>TvL6^re+$)v14scnmw|wQ1Cc9bFYG;*C|F zEbqoFv zcVIzU^P`Opw<FAQJXIXfABs+on`qv{+`;5 z4?;A_R0mIqJgUp}Mls!WFvOV{!O=jWD@QhG}xCHK-k z;T*&~5t6Hwu`Y`PO83j*Lw>L9SIB9>a|3A+(0acT{1}BXp)av0VBnUfTm}5xEd{e=tLV?)jY#F#7klAU?fW@t8 zF@ba~nlmrKG{1JSyz0~#tfvS%dn(x-NV4!187t}wM(n5$_e$TMl2;xyspz!pS>69-hL4dOxB|iipYo(p&wzoOu+pk1@6&JL@g_c-~xiV8>s5XC4z||e)TN%fnmC#jr58lpSS3O;S zd0hJ1g?}SU?;xz$-`k);+0CIkC#?SX)Z_YM_s&w+rBBfeZliBQ%ZCaLwV{M^13xS( zO-r0157V?*Mjz$hxaBwlHIA3dF@$yyshX;FSWCqZEm9(!gc7RmuLMh!zl@j-oLcQpo9{A%oo!lLcykH z#k^fOo_iYQK(Iv4N z%8zGpYddqNl7KpZc>mpLfe!xq6*BiwyZC(&x6c6sDxB;nbNEYJ&gF9zbXTf+#U|%Z zQ}GF!DMUTH{J_cFv(?fY&UD^1WPLD$=jH0K_s_HHPl(kx^-yKQJHGW7(Vq<4T1N|W zjBoD&|A?Jv#T$4+;Xh591j(}W_nYw-%%Ef!R^FX5Dm%}DH2G&x!3yW`A>r?9^?%z? zKxER0!h17R=82|m$yaNDbB$v~Wc2MA^4GXMAzu1@rPk>aW_LvrXdLhKjT54mo>%ah zG-AHxkMJ3vKVBO#jF@yEF>pNu^?1P9L%_Hq$V1plsCy~GwFMUDu%I+>06qZiA_OTN zyK=r+wNJB$^<_H0$^h1sLFpS5akCaz^hvZO7wGMx4!)fA{n%+cpRrI*!{VPt&UH-( zV?UNAwEF5VC6vQr{s@+M8Q9zwOa3AI#@{cCWF5Ql$>={9wmq6zO>!&?WzQ&RE-R+{ zUFeA)ZmrXG$yJfs)#?cf%6}g{fCE7YirVVr%7_CZu%cP&gCgJ`y(sVS`>J=K$PLqYiOGlT^K>>jIKisARzH=1SvpF+HB<#_&a{ic z5%E(MV}dwPlSMlN#SX} zN4ri?3(sSo$o7+#s=l)4Ver}cqO>0Q@5>8Wdv{TjfUt3NrmzgVS|Lty>6bEYcC<z4TNVuI{{fp8q^17v4uG1y_xDa#gVdMA!oTZQ{#^40Nbq6DvJ%-Sm%qDZwld7< zwIR3IpA}*c4e2I$d#LLr$9+z+Xu{OvoqANP30q(2ig&URBqcxzi-!_)dt5ZOf$j@T zwhO__^4z|%UwIQ?LkCdQbFjX-y2YIQ1oEB1*%>VpgVh4wmbTt0O>L_023yFrO zp>Ri%i#qP9+YB{^e0pUnyuGAfl(6Nn74=p>gSQH@QarsmbRL27&lzL;VOPu6=XWfh z?T|sP*|dlr8(hgJwXLXZryCn)bUc7n<-rwU9+W*yAqT1*j6ucV!E>4@gEi_pQpG9~ zQ-D(tmJb*G`&$OGeJnAPSp+3O8Z=E#Fv;c7c_K@RwEmEO0d{C*?yjZS6_a96|BIfQ zBQM&1;_kOk4|?A~W?X?Cg%@4TyCvQuz*YV4AI}kqcZ&kxOv&OmaHFtCjp7g%Zr@v@ zX!)HO4anqBA@T=Z+*r5Fe4I9RC|}pk)w3gt#R;4<)*@-}Kb=NK71q}Hsb~{i!)aJ{ zD~RSS(g3M=R&qs9A<)$U@G)+qP$y2X{?nC$Cc&c+ex87<_*Ei!7Lk81<^*rnt*3=@ zF2Ni0*7q8ICyeQrw>=!>BCBuT!x|_eNThdWTJL{^`s#v0XX8@%Qg4|wO*p(Z{m;`) z7GQ!)>7>1BDop=yiQ2g93w>v-Jg0P+rGFTQxK1jOa$iMqUfaJa@jH$4u=pN7!<7q( zwNHn)bmOq?&fh=5!X0OEiG78PhqE#RTW!9b0?Q?--W*L#wF@IdPK!eO-9?G76T@w- z7D~#-ZsjPSdE7^x>U>eS7^K=X3RKH};}uk@y}N4I{=4B;dsVonZsf`zm@*8uta(5e zd3}O9sb!G25P`rKqKogdJrP4vX^tv&6az^#@NdM94*y}SUOj1s`0jalr4ofdT-Ju7 zp0mM?&_&;mFK1D!e|v!_{=YXb#VLQF#V4?l1MsZh*2fr^VR5d~X{77_9tc3Bz*pyk ztms84!^hz#!Ob8c*RYO<#<>%|-mKE+PD^}Vohnz{H{3rGurI9j6H7qqoYFCU_VXtD;Jl#`x zbJ0rYCdaK3O*u{LTsp04bR!NSmjM}2R`u5<9_@H|IrV#Lm5X#}{aT$G4$tsp+&#v9 zsu^Tb%oa#0J_BYDH@(b@zpXi#`vYN1z80)U9e{Hw_VhnY{?EJoUe5gWlpDEXKqv!S zu=+pnnp6Gos>F6Wr+0}ROJc)o^~ODraqdc7kJ1d0-p@_*ooKm{weS!@BU)5sbRqan zooyBB)6nmcc-rLypGkoNY~*T6hv+wYwkzvRsf7TVo)29xtyVvp-jAI>)=1+YY&z&e zRf>Fn^eZYR&_}=*p(|Xzt-XBL)x`#z<&qO?Z;mR$mIw~s7L$9Nq>B{=`Rf-|#8YXCU2HeII$-bB5l2^e^x^fW)}LT4rF zizNT^-w=Tq4NyZ!muuPdmVr|l_-kP!W5}fU_Eat%H0$Xsi^^lT3uhOII`wF7%nC^M zS%AE~nV%2k9W{+3;cAI5xvqT6@Z|?T&(*_JgG``X1ZL}Se&#XX<3sIsIWJgXUuh3u z-)>0Bd>I$}5fxD+M+~9uu6OEzs@jSBj!($80Ykssa!eD%@eaT$$3WwcOHQ~reQB8B zH~}xVaN`*at^RXf44F#-q@e1m8L?lsd+L(Wu z4^VNVmap#;@uJs+!seH>66}~jf#OHuiq=u^oNAnjwod&Ne_{Dkv~_QF)Kuy{j?_;@ zY%<4hOg<-Lj2C)R1kAjeG#icUCO0fc_)O3HP8OG?xwiV0TUO-Wc-^Ob0~jO2Mz5fr z-91m5!+z`o&v&;m+o?*dbcMX4!}}M6S5t-xl=KQ?K*Ph~edP0|a(@|rAoFwEE~5|j z5dQqL2e`Snt z_}v@U|8s!`$<4qGo(P7fKI8|?J#8Ex4VaJcj=M0Um2n0mZbJU|U?#Kptvf)Vz(Qu3 zWqTKBtD+508r9j8`r+YNc%blrqrO=^`!OPs5!cu6CEvhhQ`JKH-Wini)r94VULM*Y zia_nqm%|Y!^Rh>E>RNn3Yf zSRja{QhRMI9dBGOny7YEq273yOq?C>fNSvg@Dhs*&YSh@D?=nlS=ci{)5as8=ui2z zjVlv%we&x}NzI=Pr&T!&x9fhme57pR>M##j>0sR_&R6<(%C86CDf6`Ib3159iw;6$ znhr&2u)h0dq^TNWcjlUy>OE(JH`|&Xsx*w#QJ!JK)uTO$jALfeCR5ha+mou&%Tz0= zKaGcbN_Q_&TWRt73jk%Arc>aB)U<5133P@e5ZHZ%6_q5Wu4D^)o<)xY&0lele2 zGwh7ynW{VV-C8?wIp5ZEXG4|cSIoy$W@eQ{R#Qzhz7~a?JvS?ZzuG#FlI+R%PeVmW zqgWe=5UTN?gEX^M1z6C``0`!bMc&8cTr4cHV#%8m(m$~n=f2N&O}7KTq*ZJ!2^bX} zLgckm{jTtros&eAJXo=Tp*dIG2eb$jvmYJ;HL5TBVQMM78mA}#1?QOieP!qK_-YvY z59v}$)E(I@xG!S%^YcF02x7%o@1I`DI_u}+r$)4oA*C|5Sm)p3Mk#fMW{(C`7l-5TG`xAk4mTFz-a)w#f{?WI zTCkMQfyWzPPWJ43)f#nvu9!l-57*S?eFw5K36N-6JbdJ&vF!S^wBy&n-PamGFHO=t z8j~z+EeP8j z5g=!&tktpxme2a6=YNl$Ij)vj8#l02-J5RQVo2*ZQEiSPmNak1TLko@)*IgW&lzQ& zAx5Mie}P#&RTH<4-ew@%F}U=x5Dk*AvorARV|uCTICngZyeytbWn!ex$mZF526a z{Gur7NS#g0OU{+?aeG7JUt6maxeqHi_u#4CPPkyKCsO-sxX3s+CHuW`Nzr##%H?d$ zZl5yU<6%YPDXwBF=g)Pf@jSZfF^*mu1+|U9z><+#OlUNxgpR|FYEVBERP#%GeEioD zTeuea-J%IVspL9@#?=V!VH#axGYJFJbq3p~DZ`CNYR##yiGXt;e3psf7 zXxZj7NEf+m=rX!tU78{_-wT$RP{hRcRLqA)sq<_Pr8pQ~PbL~~JM6ocvh}?mPNIK~ zDJ&`*FE_p8Q8RbvlhT^B*PZT#A9n{|sM_q#cl%ObeCi&8o%F+wVp}Vhc$S~rePwVl zyQ?R_%(bUQBW4w6`buA_w!vlbMt>}!$O!c-y`q%wL>YB^>}UKxQGL`kO1xmq3Au%$ z)OYUuDJsn7X81*0mq1Bk)BhqUj8SU5@sV(fHcID}rra-1e-5>T(aQ2BZS^P2q`1?J zzR&6p?{_y08k9af|FtyK{g{^38apCw>RqJTEm74Pzmg?M+Wzkb=gY4su zvu*DsrKF|{A6LTM<*EAwFl8P6Sy!?g63IGCC7OXH?UmOlm|JZ16Q+MtNR^ojPH{GWdxf69~z|LNSx6bYRM>*(6&aIa| zTr~$aEk@LC_)0Ygjo3|TvC@iWs2cNN>Jf@By#7qW>RUezzcj9N9@fk8-W~ks-G&F; zhyW2+Josxm;l*Kx0c_R!OjxjAIKp^)GR|W5T6bys`|QI7Pp69_18q{z+=cZ4$+MMV zTlgPjO}l@M7IGLkt8Nfzzuy?C!>f;3^yVlffUyY5dUhfCm;{|+$3kXMk(sulU}Zoz zHtAk*uW`3cXSZKK2%hdo+iRDc7ra*TV~b0gi5ZkK&6<2Tg^UZ*aJ;nEJ64jv6-YS~ z*l7$5r2BcaV7+tgL{IADaehqzVznMWUKAR?zV?J#;O>5e{o}unt&>#{3iGV}ToRQn_Cf1h!XTygirh;-GJ3ig&Icfmt`Wd-J1WQ-(@ z9yzn?7kV|T;eeB;Q+S>mv4~dZ>S7^xiS%V-wk?6! zZcK&TvkFt7*H%?5Pe+%er~HZNjjg%bAW@l-H*OI7qMfsNI9G#i7o=~qUS_;K{3bOY zTWO33GWGBQU03ZEzEZFc#~K(%oSPWcmMxI6%lQUI{nRJ7McTA$9K?Kb1k$~ z5c%ijS!3IPrZv^q7ry8U1b!?^li$w0#!>oUM1$t{q0R0u8Ks=VgnhD2up+;d@H?iq z_rPXfo?a6kd-(N5=*ueuxoDd656Z0*POG&&xqV|_)tsHZg%jP=)+@|(8lB;1UaM6Q zHJU=aMrv~@)n=C2enA595TkSb7UN})kFK2W)xT1_(l1FjlyjKxisxpDT0$hmTS>Yu zv8RM7DEw1@@bLGE-azj3LN1AEoILf*Ocu2E3{Jx5>+5S+=aTnbbzS7oAwidx`0*QH zK-aVgBI-O%1qJ3Z#Jx8^f@>cifYue39H#!y1E)HFqm^B*fAR|40yv@>HzS|A{k4Yz zpYEi{^Iw1+Uv%0&fBt;Ihf1S)sOwcq6rKLNobV|wTj8Rc1&<4iGzJC-wQ)crM=dcy z#AZP8_e|xu z=@yve#k{8*JV$nHf~M@p%9DK#4-V|bF8Ln4NxS6SMxP2GBKh$5x)3d*kMsWG07u@< zhPt_~cr~~6&#U%d>XqIE5m91(LeBFAl8dp5|CBdb{1^*{jZE|a8zR;1bDV&WI7f!d z1x^R3(*zdmEfUM^b01Dz$#F|8Q5+bp#v6s#^umAwN$;`z=C`i9`Xn(H+QE|DWp*)~ z8;z5%ejqzb&nv7LHP~MDEE3GTC_ZRnHUo6)MXotlQ59N5-i1uwmI%6w*D5jZaT~2A z>D#XSxj0sl5TVVPC}1YWo4gGRsa6+01kO_bTV~lcTCcyS`cuKPL;ZZN8v`3fd`?gn zCLBqumLKyxQFq>RnxdUI=Q;;q0KA247mz-}X1DGX z3uN;4NqcO_4i}p)@5NdLlL!bxaw|ZH>`x_TX1Uj%Ep7ZDWBvn}i`g@I3uQpAWvvR* zgBW01boN_cZ4DecelgGw8Ce8HMj^~LG@Iz-o7kh6I&v_n{P(b^aq!sjSge} z{fM?Gag&l?>(gec@jM(Lov4O8!a7zK8qImYCoiT`d35u!gVOea|JGlwzr~q#Bq}B{ zF8zk=%y!Ymxe2D@XrE{4agky&QK2eu()`BwO{IxX$09V2*hbc+R5m?q*p$Q$Ucc7i zJ$8xNS5+Z^dZO69zwf-_=omADWYmAVh*+uhCoB_FK48&}9Ljh2_C-{F_ z7v)IC3%LAEfNx!p6uj~WH2`J)f{Jyr-0JCNkcQ{co_)mjPqQ;~7Xk9w9Q7nYxqO{G zR->|K3m%BN`xDUB%z?}R@OFy$O+UpypR3=~(-0-63;<05Q}~qW_U(+%i z2jw6fR&w9P{>ib<`WrEaZ}xOkwRC*7X3H$wY^*W#4^N#vJ0@Y_7w222@;{&Jk*n?- z1^IbpQ2^ii&a)T5xqL65C{4n(E1Yuj_R{*BpAp}g8lnHWpK(=KJA|^dFwmstzQq{q z7i(#|YX0X9u6fZ6yGUM;nd6kGMMhOl?`<$I*@ zOR$=TKRj0z@Mx%`gspp`fRB(O}cRawHehpkDD%(EAnxN3rq+|8N?(gsK8y+1VU=4=L9GAPoXNvIGNhfB=9Nq@m-Jie8(tlwK1^P69aJevgYCUWW@WGrY#CE%5X5y^&J~P z7Tc*LP}<)*j>>u%Ir(B?I12^O{OWHTZhZJ7mS-=)VW*(LVN{kQr`Y4F1I72XT%pj{ zGkJawU8v12g?>3NPydKzh}Sjcp|cBZX8zMbAjh;}U8q*xaw@Sx}Ah?60sjfI2gCO zkb3^88oL@oBSjeT>sggW0ed_Q7U9M9AfW)5vjx4)IN$uCPZiqmxm8mb@~^0Rk;f(( zEL`GS3pS0Me0!i}r2=e(yRgJ^NFJ8ae!;apkA8femnoA2I?TeFpps#(Qf2E{MF$oI z&1G)u2*7jiAx7v;*de~hpTS1Y3rb4~5X5!hJc7|$#taL;QQCA0Dw|t7+OL>ZvS|xj zJX-7A3kO0h>=6RS1{UpdnK*Zjd;A~wsBx&Ga(kbOHT$f%NIhRm4I7QlelSteQn1Gw zV4_+vnjjh^`0w|3#rFY{Nuz{|xc9w*P9M*)}AGC0Y zq~ksW3veTNnsS~lT@VX6Zo>#KvgrQe0%(d(e0Y9YzEJ;t#vF;Dn<|G%=ORO|0cp$C z?*N%MBiq7VK3(Rr0HQ!(O)tSo4B?m61sdWst$-CAg@p$J||FrZ5C&2O0?3 zQ|Cw%W<3VapX53`y6#*JZnZMYSY($5b>qiTF*bl|<=mV8^Dy=ew8Tk+U~R zd5WDgY@nK{&D&4o-zL2o*Q+cD<4I*XNSg)`f}Q^anmGO+{(v`zEAc*5`WHfM5|r zAHwscT`X+y=XXuGrweo9HQ*4&c2{mM28wkT>U#jH+Rm$2^HLA$uOI@Fo)c{36zXT; zl_pUL1&Q4g;%lM-o-DTqD{Q}A#nnot26KWxet~#b(90}`^cjjRAa}%=V#vpR!(sv! zxy$CF8LAgWw)11g=?%HxNg+Z+pjvGFyyX7)So<<0@MvK0w2GRvmLzCR3~UTcJsX;t zdLI3w+4tIV=>Du}q#hL|mFUrr_3zR)yK`AWTM})dy_3q#0_TINN$Y&Y>BFhwnGVaM zFEGY*4G9g?PyD9C93+Blo*>khlT>?gOML`xW7kCQ@K z10JR+AdT3qhxoA)U@$0Vkb8M~O+PJ9+)n#-QQXmQI4v_Fd>&%yu2{p)gdxE{ulY-z zo_(I=@~0`>ttk*r*|+d=&>tr<61DmwHc>b`sSv}1NEixfiiL0Ae#)CqNJwbxf{a;U zKu8%Y_LA@T_i=q?bQ^uo-wSx0t63@E8pVtq@#kq(*3Lb^O2t7?MZzX|>m(3!Vj$UI z2c|QPBO@b|VK(Q=El5pNV)|M)28@Q^V6Pp9E;wg z3(IdpwcVV7>@@{UlQ0OePH8p)l@^>>0+r=XE868TtllMri16CekuJ`%F3VA zHX0giJ1N++`VLiBVGueu3C*FzN(kvmkSD*1QYTg<;(<2~fHOsRbFZlI2lgAVw^iGYjZ$21v60E4J18@z(m0Ck>(YTdX8SBwAY z-+AGD0no0NVwT8UpkVAAosJFnA58j0Xe@P64sK|(bl^{bY`8&OZ>9BOuT9W|*}3)eev)CuvuK8B~wnM5)hHO*4pT!r z;8QtTE-jG=r}fjuOryY!u7~NEs7hzqzUx;Q(4%3WoIiQh34kxwfG`?=4-rQb3wgMm z4i?|aW9hDScLjs#=dshZ?t4gZ$`dr2KCX2wDna4|9tI-s@37IcCSxlD zwD%b&fu-HftwX zlz+;?xlBw60B%_r@$0r4qBh*L}4p*~UoVB<9)+!p4hwtHGZ& z8D66$?(_Ueyx98!z#od(%t~1oF0rtDhw#u0v2AkV?GqM3g|r!I6fldTAr@&s<3bB( zjF611wV$tdl}h<%pqar#8u^Y}JW-oac}u>1jPb$(@3w^snoN`_NIHlW@Y6ZH;(k5Q z^o+>?Lu!OL;B%ksFxyRG^jC^gG*LH$1EX>d+mC(lo=bt=mPN>f_9v$A>G>LS_PIBV z6C<8_d$&N}b(^sa4DED5xb+cO+8GiHTL(bTVKoTrG@A+hRPH2`$8`<}?kmYH#ki1ZrHRAU&cjr*+hZ%JgHU#1-PP|3t=j+=zO5E}{BoCfE720gAI4k7d@nH31lT4C%z5eb z+7G%b)Gy@X9+sOtnZ&ml2EP2vq~5ecSe`lQ&{#_uMwqydOl{Y5h0PT1w~yfQOjx&V zeH~qp{GjiVmV`|BSu;$YuzGl&Q(zelZI3?O?w|{o3QsB<4wSmPa5k=L+}I!a-0ymE zedUs2Ut*E#mUXe(N&a13dbf9+FUUj0y1x1@en_XQ z^_=Pc*qb7Qrn9CeDWhKYC*KX!GrsBR>8ARYkX071b2RXTd20Vz12qU16q}kwRwG=+ z-${N&kuV){9-hGjo!+Ejq@=E`t!)v)6`+l;hk;D0e5xegg$ss+=X+d9%zk~YA{2yM zLamTn@q|OIkThG*imzZ&-_)HO&gL)~GIFlGNlJX^^pP=&mf}M7Qrx9Ty%C&)n;ydz z+-lRR`G$IGoYtNxtDBNhhqH~2Xz8*(9dXJWiXDs^e2|p)&O3c$mI4F_1d#YOZ)2y2 zQBeAGHmS3gK*LOpmU~^f)LaP*6Eh@JAzcz4hAZ^^`X_UwIgC8*8U{}DPi%bxr7%Fz z2K^%yq(8geN_MXZq8MKLG&jig#>o(dS|MCl*j}3&B1S_Vpn4gM92GrKCj_U$Sk0Q@ zZArMo1bB}15H^e!=skf*M$P*ynf3Ur;QERnlfE_JNCmLmtpP|dVN_9=@$G!6iS01XV7=|`hM}RM@-J^;002#|i^)?`AI7ON6-}Trl}cpa+8hp==^_l16~n>mt!0Ux z0oT@z?q?E-B9k?D)efxgo2lk%hV8w2@)VoLies_gevQr5rA3}I*wQ?@EzM7XxSy7G z;B$s%rQOFGSEn7A6KMWSoTeKxHD1e5hWL_C*q}h=`~+E-`>Kx~5K9^l50A4%RA|Rl z=0pyvKYM461l$3vcA#~A@!&?Il?hs|`aMWn#g~e?YW#{}&gU5P_{+(0KIa9LwU(A} zI+-c9T*A~D2~$jJC2~s2TL_CaW?B~)sBG1)X#&p_s#=V75>(Cte$cIlWe{e(8uFBU}n>Pa$d;2(brdofCt*SE(nY}=cUpCc~j~tQF3Q=!Xrne=_40W z?VNaxJ1<^wSgvK9^djN?=UnO3ks8H*-&vM) zvX#76$*#?(3~H_3LZ zr(TXc_3?>YT2D6;s(JW2e{Q8p-S^OXCo^q0N%>{bb*&agCQ4qfoO_FI z4DCg(oIw-AuW;Wh;|Jf<>8{H%A9V_J(FmGImdMYaLrP&!h10580Y<>Fn18nd6US7= zOnF&evd6Ml&=&B&?5>1E#JID^tu%l8ea1;S990j-!IQAgkt5u^JK2jjSPYqkL3(0( zc8-keGmyaTIV}2fCg zkIc%s3H9cW--NoZ{+%~=s!G0gn!y2S85HJ|WKT&Iq=kuW;vpDRo~pDMVCh*H`8D1V z*G3bNQ_7U5seG^y1qKl!j?1Gh2SP1U()a1f3ueo+i@pyqLKRp!nSG6(&GS!3vz69@ zZ^q1#NBaee{BDOGg_1Z@h7X@w9@OT4y1M6}?`V=_h-=eoIM^)SQn-;Y+V$d|ol*zY zf?%szIQmKXTB2?W*G=YC>Vvf`npJr@7F8jH@4itzRY|Kc|0AX)I*M9)NeW+JWwerN z2+&>0tIwH<`@;;)Ur1-`RKPUK@M|xt-mU_^HM3uN)WCHKmGR!B-CCo|?&B^RZJSZs zIrx&fNfvHV=t@f}SD4r}=!)mlMZT3L20tjuq1`gOm2bqikQ6nk(IzMLD%a?+AFC?r zAm=&LH+8z%51XTFaoTq;a~S$AcqGThDqzoI$p{o?$}qm%hhW)rSZ6oia-RRV9m*t6 z4k(%(&#cOL&hohU{z;4nvwt)7X`7Ne1UQbUW z^Oxz)7Z#4aeH5H(Vvl~!D9GnfP@zXb6z)x6Wme9Kfo_USVkLqUw*W6j(7nnH%9MNg zh$@x?IOc)BPAmq71A8F=w((B~L5-d=A?~omgmPK3hx+f{7dz%pYC$BnKjCqnC!QOq z{i;6(VWiRiiu(Et-o+gcxR`68+4Y)!x^b~*IQ)Sesr4iqr6x> zak!oUB_++?roA2OePeo6&hq`?)-qT5Oq}=|N$huiR`0%|6M#`qr+ES{9qWXcodJpJ z!|CH|h>mwvS3`_56&67+X~O7eOM6!M~u@GBgb;@)h34M2(~j{)-rkP;=k zV36S+*AHP=aRFUstyvG#tn>K1UsLsPRiBVm;uU?h5W~+2?7i1_KA|G3JX6LNLjVV? z`1^9Aue)icN=CLjBh#jsA6KuVukXic|J9c?>|kr7Rf43vzy3P;fMMj{0p@B0WsJVR zhv{W@{igu=a$pG*S(sy)_7G@Yw}G&OU=a#;DS)n(NpSYt-;)Xi^o67!%gcFxOtbcI z*CINOEZkPhYo|^-bZQ~5rMR!CjR$6Hlfo-&LM%!nK^KA@{PJfn5tC8~#MP3IuRjzL z)lX3vK~G>O?!R_jv*^kj%9pisQ+}5!jo!n&ZP>A7=;wumjs)~{RO&4()YOfQsoa=u zU;!1zsw4Q!KV0|tYunsLJJ?eo3f~64l*~gHTQ*2)<^y@mLPz_>!0MKkr7mz>QU@0o zEyYHl3x~o0;gg@S@JXKGN%S_+f#S&<*X7+u)3fkmo>dLSfDVPf-+wh)+f1 zXv_%=9z@G#(a%H-3>dXZu(O;BA|zc+dF6@l`2c*uyL8F?RrhXWQ z>wzN`YASYSj@iV;gq=)9dId`M>S8$#EFJ@noTdiM)e-xf%QG!ZqS-T1G|a^#DL0K& z<6{PYf}!<^D3_jc;0E3knfKP!@)nn~`}?3fdco|~e{8~IviUsp#ZOY8jqU(XI=vCar==x`$AmxO-}$qm9>z$9kerRh@bK}Mn@F+nRqH%zb`sRo zp%*a(ynZ_EuU~vQ>Lg)9pn5=}w>#W-E*{KQrhiSL%Uq!U{xpDIQlF&auGhfHSl!$_ z^{+$6_VD{e28I{3;tY%`dDjOd%sQD19xN#Lh@zK*(8px0M~sYj>!~m4&zs_Yf1Q%e~a3QrQ~ic@7KxGJw+R)(KzyS*0Q<9go9o2(koYzb2N~-q_FAmyJMg zLqA{nDd4F^`0bBzU)&VVKDS`r4wY`;X{WD^e!yL)GQmu`c-$h`T=at8rxjXj8Ghh> zfDQ4^dp&(B+yR2_`Kxg;24+%c#7)w^oEESoW~CQLnPPC8LAv*qBH>4?47 z#AetLrvx+mcKez^J~-DsN+D*L)ajmigqhiQ)VXW^_zcwZNfMvhlVBr(rlor8{zr`( zm(tjA81Ayb*7{fa-cqDiP4N*d`md6>Yi_Q?aitZOX*~ql3JI$!YTYUmAlLNzW0N>yxrO5v2q34hOtLi zYyZj<7x&7M&vQ8&`$O3={_JZpLpYT(8b#-S6?Ha9ml8e;GfVIZWNd^gNeSw+=+mL> z)F;0}hkFf+%a~dnOF8@b&hBoSc1YmjM-(s}!&$Vdn&Cvep3ck`n`a376)1eQCIGue z$Ro(ibZ7#kcD|BP^*Cs*n4@o;6%Zx;HN}^=ye9!oV()six5RCIv9t+I7w2aJjVA1# zUx?e!!tR^X&jWOTAQ(L_dF7+9G>bCYg1<@CP2j5yveuFfD`z6t?{<3)eQ zy@rHr;HL(nileon#>>&gdp@d7rC&Bnusw|xv;(vVtTDPu$H52N6(wZsT8C9OqK$k( zlLj(31AQat+=`pO%XUm2_;k?>d|wa0jbd;{oB?U%t>$N`n<{U!k8dnYK zmw%qbAnF2-0~Z7-*xwk?34R($Cr6qINJ3?$@FUQH4~E{NBm8+u(8FZv!_fI29lBv* zV+WM#|nmTZf|CW6dr1kypSuCPi98-M_AyAs$6?? z=&Dv^=*RE2eRrMTXKX^d%E2rUx1hQnh`EN)4^2~b3G<3qSj3>Z;S2aw`Od4fmjssNnBwt+zRTzikbf%NfLHJ;0QHL? zI-!Fm~5lAON5sw#ggq^OOggyk@`f0X5mY=-HM;3d?g%? zvC*!yA$bHk;re;rZ7!hIumid7ARp$*Je?tSGo4mp`d~N93I!Sm(esT{Lh5Un{6NE^ zq@;XB`sK@);Qc)B8Rq;2xrK4&y$@wccQRHiiZA33B-sj-w>R&)x77x_G8-S2EgHI(g6{NehL03i`qqcJP3N57`Ypm_7nOm^BJYIt? zr^uv>bg0xK8euDSYC*$IkL>gTd}U}@V1y#X5DlIrq9kB}UG7tX2}_5`DoCnm>G@jT zIULhk+L6Y9P=^1LA!b`$_PU#QEtK$FCW)5{`6`7W1c(wPGRmj;YJ#K2=XYqcvoWktCy> z7LnWk#Rbr47+ClU-l&C{j$+42vi>v1{=vZ%bV`9)r{Wn^SYp}qP&1jM2T#7Bek7Gn z7UhhSl6(7`M8=kj`;^X5)LbEO&vaVn&+Tf!wi2JO+(ae06wgA@~;i2@d1ktRxwJP@G{l>k4j%<6Skqq&f})iz@I zG&88W&s|t_%p;nxMC~4!!wYgeI^55YEP$vL3gNArf19soD9Ci}eKmlx#mVt3)K+FR zk`cHy#@gl9TA6@Kt)00ecl_w_cp*T2`xfnj=;B7zB;=!=&Pnv9VBBv+F_qh4mSYbT z)(Bdti|_9>);+3`+P9+nDasp*9F>{*G7iYJ-|zX) zz(k@X%zAodyl$MoGa(_bi2K;?==c54pJ z$~>-`NI29e0YWT?`>sPvl2BbhdxY8Xm?MM(6&JG#C1)$5Ir_t8*#O9d)5BUcb<%kw%NI)kT&T(Pyqzh$3fg~2seRjtm8WjXNevL%e zB(NxHQG9HK#`=ucFq5=d=g|QTf>iGV$-E~|YQFRbf-^%sVVWnC27}f<1DZchGNhC+ z_QLE&0>rmCZ`qARvjvNA0tUqp#A0tjDB-mv%Y$7BD=*>zmeziOn_nxqlQ3d>T{uLo!p?|=;K1JaMRlJ+wrh;A1u;x8yUReXn8q)}FE^!B2ZPCxeN#{Nf^BLdc5aodCw&Z7yrO+~5#d38<99}S%4vPTvg=(9}_RL74X3Ey_HFUJKwT<_I&h9HXV5rb0@+f#=BW3iv!&EClrN==PIy!nY z^fetnKwTF*1MF_Xnz`1hxverV0eZ{ta31qOP)wx$9)`nt{9NPoT-8GT=^s}vT%d*$ z89sVb{EFq@WhP7V(IFXh@~~HdZT>l+R|@a|(-LzSdSZJS;&)rb0TGcSplfc1r7W%G zraBfgG~;1_xP+5r3o+L%?47)jyoNCT^>xj-M1@{^tKHGH3WvEc68?v5{kTa`sfM?| z4Cv^=^_3!LW9w#8+y*1ZrUBYA$8Oru+YR+yPUo?uQr};QgdHFulU28a@I1}Lniw` zUTf*Uoc8LNrb~6&Y)kjyg^D*E=?il=9@KB^i?^5AYVAE=h%04g=|9UZBo<|1X?yT# ziL6{kbEU~mpzuI7_(g~yX?gCHz`}xCVaKZN3QP_T-jDXLxoWPwCwQ`Ka;2J?T{X{Y zo>RPyQ=-kj?Ey@}!|dt;#&ljkD$^i!Nh%Z^@E(Ld(gaVpl*7ex2D9Xr3xxg@n3gYZ zHWB}L@TV6sHfw9Y`^~T#;Zw0>Alkc3VwVdHL5$1bPOyY{fGG49jO`~9Q((5#gYQEznpxbr5_7Q(foX8eZersvJe zDjK=8-LNjQe=A*X*frF*lsL_ip z8{g#JhH-%M&>QDswT=^ghbQA{QzKd_6cd52)+%Q8W&)HCsX*MGrd6y#V`E}!r+#E% z0aJ~2V2>wy?3xYS(RDm2cmN|WJOm<1ntu9WO{NTy7MLakf=3!7*LpoICbg{aeV@-j ze9qCT?&n`G7C$La`p~c6yVsQ+$*Q9bj4O-81?SV3P*?=rt?w2F^0|Wnp`>weDm#%y z(4#we^&+7j41wF_asy>W>Xk6kSl?V_JgQ)sD@qGp;@#JL5Z5y;YNT4u(@xJJF(d6$ z!y0>dHl+G}k<>w)2gfo2g6=ikOh5kAC)9rgeGRek0s?UyLF~p$qNH4vk`n&lN_G2p zVtVIJ!mNrgE9p#gXoI3^(S8a4z~!~|Q#C*cpjk;?_wjszfnZ4pOb1BjoQ$KL@GIPQilh_y)jW2lh622f#;s!sgSHnMqp+`m#{R&;s>5c(Z%u zZq$H-t7h+TFp?|*CQsCr26LN>s&B)R~C*Cpx#{wV!@<~_q6RZCDA7M$X(OP#6 zD6~ZJjosbc+B?qWXvWG9uOH*t@H_kr-@ktmnfqK_j?ma;NyGGaCVyV^iYLORrWqg` zX=0k*fXLqp!a^G8D9q>8GvOI=OuLj59UaXV!X`#{z5)s^2%a$*vn6Ilq00U*|Mfuz zS(3+7*Y_SlYY*9?jfx^)ZMWc%c)%iRz$%zylewXx;q`lSKMkE=D;D+{;{(_B3abMx zs$!n^`(`^%N}4MR3+!9vf`o-NM-{dDt}C_&LM)C_I#tg%_;a=j`O6P?DzZ}7gM(_pU}O*q zss-vKM#&_>8VR>P^g%FPqu$6rwJBClgYJ>==;m3HTINKx-qzM;92WL;*aFRA>2~W4 zS+pm>9;e2_rRh+UvVJ6Mk}^WXy}qplZtsq_Tmkj7_&_xps?)kt)FR8`kWZN}$xU`{nNrmRhJNa=fHbuTcZ(P}N76 zQX&2OH<`yLMC$*3FQN9_wwTZQCe1c{D3{Q?KQhZ*co&Pdo2i*7WhO}g^&KoWTR{;$n;#M6uDu7?)K(16W#}?L_k}R>Lk^)7m-Tm}@5|(Mn=P(MP7H ziZ&?CDTR|eV{l0JcaI8x{iPVoQtV;nyN6P+kfNv^>R zrv=fS0qe&O8p*3cFv4vE@y$dhfBTh_sn4+iI32B_&-0Hd?F3{Td^UXO_p3u>bh3o|m!OHJn8^NvoLC|GZ`NXl&7% z-9Ak3^H;X?X6hI0#9RmON5a00GFPh6*OlZ(D(&{cz*tm}#KHeRUg&@PQCJ$u)U80P z0Suh82(&1s_tSv|M=I!caYG&O(VvV(0BcTE>;E{r@Whe()W7RfF&gmFu=^^Rv9HAT zOk+C)XMyk;uPE(YL`wmYwbTcD?x{PGbSVZM(jWIKnYe~3G>r!9>xH4O^XK203=acu zig?`Pq0?_3<^O!gKVSmAI9{jYxHw1wZg%O;s^x$eNG0++PlAz@@1_d~kQ&Fwgaad4>b1nV6fn>IFwFw0BjJDktJQ&Dd?vE?OXlFJHwBju9%u{9^M1ah#9Fm z#wMt|dT6y%#LwI3OM<7cA&}8vwl^=P3-JAAGnh)bda_IX`@#PEYT!{6eBD|oa&}54 z;oTArB7oC!{^{b^JE+bWoOpO7T5Oif&_B7{sv2l#(#kd|n)9ucHW~!hsw506s5v;+ zLj6qIV|p|VAA(I2!h=Ad)Oef!^KGcF!2mpl5g7uXxy%)lR9FgK6G*V$P$G6=5@CpY zHsFPep)v^E3I96Xzia&4vn*UgCl z;zovYb-|

afPgi{tnApa0IpUhGlxm`M55E!~&|hS(|w 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 ROu)a@#-__JFWa!^e*qfh*Yf}X diff --git a/docs/source/types.rst b/docs/source/types.rst index 6322b29b..253994ad 100644 --- a/docs/source/types.rst +++ b/docs/source/types.rst @@ -82,3 +82,62 @@ SchemaConfig ============ .. autoclass:: neo4j_graphrag.experimental.components.schema.SchemaConfig + +LexicalGraphConfig +=================== + +.. autoclass:: neo4j_graphrag.experimental.components.types.LexicalGraphConfig + + +Neo4jDriverType +=============== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverType + + +Neo4jDriverConfig +================= + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverConfig + + +LLMType +======= + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.LLMType + + +LLMConfig +========= + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.LLMConfig + + +EmbedderType +============ + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderType + + +EmbedderConfig +============== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderConfig + + +ComponentType +============= + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType + + +ComponentConfig +=============== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.object_config.ComponentConfig + + +ParamFromEnvConfig +================== + +.. autoclass:: neo4j_graphrag.experimental.pipeline.config.param_resolver.ParamFromEnvConfig diff --git a/docs/source/user_guide_kg_builder.rst b/docs/source/user_guide_kg_builder.rst index b758767a..87ce2f42 100644 --- a/docs/source/user_guide_kg_builder.rst +++ b/docs/source/user_guide_kg_builder.rst @@ -18,11 +18,11 @@ Pipeline Structure A Knowledge Graph (KG) construction pipeline requires a few components (some of the below components are optional): -- **Document parser**: extract text from files (PDFs, ...). -- **Document chunker**: split the text into smaller pieces of text, manageable by the LLM context window (token limit). +- **Data loader**: extract text from files (PDFs, ...). +- **Text splitter**: split the text into smaller pieces of text (chunks), manageable by the LLM context window (token limit). - **Chunk embedder** (optional): compute the chunk embeddings. - **Schema builder**: provide a schema to ground the LLM extracted entities and relations and obtain an easily navigable KG. -- **LexicalGraphBuilder**: build the lexical graph (Document, Chunk and their relationships) (optional). +- **Lexical graph builder**: build the lexical graph (Document, Chunk and their relationships) (optional). - **Entity and relation extractor**: extract relevant entities and relations from the text. - **Knowledge Graph writer**: save the identified entities and relations. - **Entity resolver**: merge similar entities into a single node. @@ -34,7 +34,486 @@ A Knowledge Graph (KG) construction pipeline requires a few components (some of This package contains the interface and implementations for each of these components, which are detailed in the following sections. To see an end-to-end example of a Knowledge Graph construction pipeline, -refer to the `example folder `_ in the project GitHub repository. +visit the `example folder `_ +in the project's GitHub repository. + + +****************** +Simple KG Pipeline +****************** + +The simplest way to begin building a KG from unstructured data using this package +is utilizing the `SimpleKGPipeline` interface: + +.. code:: python + + from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline + + kg_builder = SimpleKGPipeline( + llm=llm, # an LLMInterface for Entity and Relation extraction + driver=neo4j_driver, # a neo4j driver to write results to graph + embedder=embedder, # an Embedder for chunks + from_pdf=True, # set to False if parsing an already extracted text + ) + await kg_builder.run_async(file_path=str(file_path)) + # await kg_builder.run_async(text="my text") # if using from_pdf=False + + +See: + +- :ref:`Using Another LLM Model` to learn how to instantiate the `llm` +- :ref:`Embedders` to learn how to instantiate the `embedder` + + +The following section outlines the configuration parameters for this class. + +Customizing the SimpleKGPipeline +================================ + +Graph Schema +------------ + +It is possible to guide the LLM by supplying a list of entities, relationships, +and instructions on how to connect them. However, note that the extracted graph +may not fully adhere to these guidelines. Entities and relationships can be +represented as either simple strings (for their labels) or dictionaries. If using +a dictionary, it must include a label key and can optionally include description +and properties keys, as shown below: + +.. code:: python + + ENTITIES = [ + # entities can be defined with a simple label... + "Person", + # ... or with a dict if more details are needed, + # such as a description: + {"label": "House", "description": "Family the person belongs to"}, + # or a list of properties the LLM will try to attach to the entity: + {"label": "Planet", "properties": [{"name": "weather", "type": "STRING"}]}, + ] + # same thing for relationships: + RELATIONS = [ + "PARENT_OF", + { + "label": "HEIR_OF", + "description": "Used for inheritor relationship between father and sons", + }, + {"label": "RULES", "properties": [{"name": "fromYear", "type": "INTEGER"}]}, + ] + +The `potential_schema` is defined by a list of triplet in the format: +`(source_node_label, relationship_label, target_node_label)`. For instance: + + +.. code:: python + + POTENTIAL_SCHEMA = [ + ("Person", "PARENT_OF", "Person"), + ("Person", "HEIR_OF", "House"), + ("House", "RULES", "Planet"), + ] + +This schema information can be provided to the `SimpleKGBuilder` as demonstrated below: + +.. code:: python + + kg_builder = SimpleKGPipeline( + # ... + entities=ENTITIES, + relations=RELATIONS, + potential_schema=POTENTIAL_SCHEMA, + # ... + ) + +Prompt Template, Lexical Graph Config and Error Behavior +-------------------------------------------------------- + +These parameters are part of the `EntityAndRelationExtractor` component. +For detailed information, refer to the section on :ref:`Entity and Relation Extractor`. +They are also accessible via the `SimpleKGPipeline` interface. + +.. code:: python + + kg_builder = SimpleKGPipeline( + # ... + prompt_template="", + lexical_graph_config=my_config, + on_error="RAISE", + # ... + ) + +Skip Entity Resolution +---------------------- + +By default, after each run, an Entity Resolution step is performed to merge nodes +that share the same label and name property. To disable this behavior, adjust +the following parameter: + +.. code:: python + + kg_builder = SimpleKGPipeline( + # ... + perform_entity_resolution=False, + # ... + ) + +Neo4j Database +-------------- + +To write to a non-default Neo4j database, specify the database name using this parameter: + +.. code:: python + + kg_builder = SimpleKGPipeline( + # ... + neo4j_database="myDb", + # ... + ) + +Using Custom Components +----------------------- + +For advanced customization or when using a custom implementation, you can pass +instances of specific components to the `SimpleKGPipeline`. The components that can +customized at the moment are: + +- `text_splitter`: must be an instance of :ref:`TextSplitter` +- `pdf_loader`: must be an instance of :ref:`PdfLoader` +- `kg_writer`: must be an instance of :ref:`KGWriter` + +For instance, the following code can be used to customize the chunk size and +chunk overlap in the text splitter component: + +.. code:: python + + from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, + ) + + text_splitter = FixedSizeSplitter(chunk_size=500, chunk_overlap=100) + + kg_builder = SimpleKGPipeline( + # ... + text_splitter=text_splitter, + # ... + ) + + +Using a Config file +=================== + +.. code:: python + + from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner + + file_path = "my_config.json" + + pipeline = PipelineRunner.from_config_file(file_path) + await pipeline.run({"text": "my text"}) + + +The config file can be written in either JSON or YAML format. + +Here is an example of a base configuration file in JSON format: + +.. code:: json + + { + "version_": 1, + "template_": "SimpleKGPipeline", + "neo4j_config": {}, + "llm_config": {}, + "embedder_config": {} + } + +And like this in YAML: + +.. code:: yaml + + version_: 1 + template_: SimpleKGPipeline + neo4j_config: + llm_config: + embedder_config: + + +Defining a Neo4j Driver +----------------------- + +Below is an example of configuring a Neo4j driver in a JSON configuration file: + +.. code:: json + + { + "neo4j_config": { + "params_": { + "uri": "bolt://...", + "user": "neo4j", + "password": "password" + } + } + } + +Same for YAML: + +.. code:: yaml + + neo4j_config: + params_: + uri: bolt:// + user: neo4j + password: password + +In some cases, it may be necessary to avoid hard-coding sensitive values, +such as passwords or API keys, to ensure security. To address this, the configuration +parser supports parameter resolution methods. + +Parameter resolution +-------------------- + +To instruct the configuration parser to read a parameter from an environment variable, +use the following syntax: + +.. code:: json + + { + "neo4j_config": { + "params_": { + "uri": "bolt://...", + "user": "neo4j", + "password": { + "resolver_": "ENV", + "var_": "NEO4J_PASSWORD" + } + } + } + } + +And for YAML: + +.. code:: yaml + + neo4j_config: + params_: + uri: bolt:// + user: neo4j + password: + resolver_: ENV + var_: NEO4J_PASSWORD + +- The `resolver_=ENV` key is mandatory and its value cannot be altered. +- The `var_` key specifies the name of the environment variable to be read. + +This syntax can be applied to all parameters. + + +Defining an LLM +---------------- + +Below is an example of configuring an LLM in a JSON configuration file: + +.. code:: json + + { + "llm_config": { + "class_": "OpenAILLM", + "params_": { + "mode_name": "gpt-4o", + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY", + }, + "model_params": { + "temperature": 0, + "max_tokens": 2000, + "response_format": {"type": "json_object"} + } + } + } + } + +And the equivalent YAML: + +.. code:: yaml + + llm_config: + class_: OpenAILLM + params_: + model_name: gpt-4o + api_key: + resolver_: ENV + var_: OPENAI_API_KEY + model_params: + temperature: 0 + max_tokens: 2000 + response_format: + type: json_object + +- The `class_` key specifies the path to the class to be instantiated. +- The `params_` key contains the parameters to be passed to the class constructor. + +When using an LLM implementation provided by this package, the full path in the `class_` key +can be omitted (the parser will automatically import from `neo4j_graphrag.llm`). +For custom implementations, the full path must be explicitly specified, +for example: `my_package.my_llm.MyLLM`. + +Defining an Embedder +-------------------- + +The same principles apply to `embedder_config`: + +.. code:: json + + { + "embedder_config": { + "class_": "OpenAIEmbeddings", + "params_": { + "mode": "text-embedding-ada-002", + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY", + } + } + } + } + +Or the YAML version: + +.. code:: yaml + + embedder_config: + class_: OpenAIEmbeddings + params_: + api_key: + resolver_: ENV + var_: OPENAI_API_KEY + +- For embedder implementations from this package, the full path can be omitted in the `class_` key (the parser will import from `neo4j_graphrag.embeddings`). +- For custom implementations, the full path must be provided, for example: `my_package.my_embedding.MyEmbedding`. + + +Other configuration +------------------- + +The other parameters exposed in the :ref:`SimpleKGPipeline` can also be configured +within the configuration file. + +.. code:: json + + { + "from_pdf": false, + "perform_entity_resolution": true, + "neo4j_database": "myDb", + "on_error": "IGNORE", + "prompt_template": "...", + "entities": [ + "Person", + { + "label": "House", + "description": "Family the person belongs to", + "properties": [ + {"name": "name", "type": "STRING"} + ] + }, + { + "label": "Planet", + "properties": [ + {"name": "name", "type": "STRING"}, + {"name": "weather", "type": "STRING"} + ] + } + ], + "relations": [ + "PARENT_OF", + { + "label": "HEIR_OF", + "description": "Used for inheritor relationship between father and sons" + }, + { + "label": "RULES", + "properties": [ + {"name": "fromYear", "type": "INTEGER"} + ] + } + ], + "potential_schema": [ + ["Person", "PARENT_OF", "Person"], + ["Person", "HEIR_OF", "House"], + ["House", "RULES", "Planet"] + ], + "lexical_graph_config": { + "chunk_node_label": "TextPart" + } + } + + +or in YAML: + +.. code:: yaml + + from_pdf: false + perform_entity_resolution: true + neo4j_database: myDb + on_error: IGNORE + prompt_template: ... + entities: + - label: Person + - label: House + description: Family the person belongs to + properties: + - name: name + type: STRING + - label: Planet + properties: + - name: name + type: STRING + - name: weather + type: STRING + relations: + - label: PARENT_OF + - label: HEIR_OF + description: Used for inheritor relationship between father and sons + - label: RULES + properties: + - name: fromYear + type: INTEGER + potential_schema: + - ["Person", "PARENT_OF", "Person"] + - ["Person", "HEIR_OF", "House"] + - ["House", "RULES", "Planet"] + lexical_graph_config: + chunk_node_label: TextPart + + +It is also possible to further customize components, with a syntax similar to the one +used for `llm_config` or `embedder_config`: + +.. code:: json + + { + "text_splitter": { + "class_": "text_splitters.FixedSizeSplitter", + "params_": { + "chunk_size": 500, + "chunk_overlap": 100 + } + } + + } + +The YAML equivalent: + +.. code:: yaml + + text_splitter: + class_: text_splitters.fixed_size_splitter.FixedSizeSplitter + params_: + chunk_size: 100 + chunk_overlap: 10 + +The `neo4j_graphrag.experimental.components` prefix will be appended automatically +if needed. + ********************************** Knowledge Graph Builder Components @@ -63,10 +542,10 @@ They can also be used within a pipeline: pipeline.add_component(my_component, "component_name") -Document Parser -=============== +Data Loader +============ -Document parsers start from a file path and return the text extracted from this file. +Data loaders start from a file path and return the text extracted from this file. This package currently supports text extraction from PDFs: @@ -92,8 +571,8 @@ To implement your own loader, use the `DataLoader` interface: -Document Splitter -================= +Text Splitter +============== Document splitters, as the name indicate, split documents into smaller chunks that can be processed within the LLM token limits: diff --git a/docs/source/user_guide_rag.rst b/docs/source/user_guide_rag.rst index d939ed85..2b2b528b 100644 --- a/docs/source/user_guide_rag.rst +++ b/docs/source/user_guide_rag.rst @@ -397,7 +397,7 @@ However, in most cases, a text (from the user) will be provided instead of a vec In this scenario, an `Embedder` is required. Search Similar Text ------------------------------ +-------------------- When searching for a text, specifying how the retriever transforms (embeds) the text into a vector is required. Therefore, the retriever requires knowledge of an embedder: @@ -418,7 +418,7 @@ into a vector is required. Therefore, the retriever requires knowledge of an emb Embedders ------------------------------ +--------- Currently, this package supports the following embedders: @@ -485,7 +485,7 @@ using the `return_properties` parameter: Pre-Filters ------------------------------ +----------- When performing a similarity search, one may have constraints to apply. For instance, filtering out movies released before 2000. This can be achieved diff --git a/examples/README.md b/examples/README.md index 95f9443a..2faed5f8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,6 +14,7 @@ are listed in [the last section of this file](#customize). - [End to end PDF to graph simple pipeline](build_graph/simple_kg_builder_from_pdf.py) - [End to end text to graph simple pipeline](build_graph/simple_kg_builder_from_text.py) +- [Build KG pipeline from config file](build_graph/from_config_files/simple_kg_pipeline_from_config_file.py) ## Retrieve @@ -93,6 +94,7 @@ are listed in [the last section of this file](#customize). - [End to end example with explicit components and PDF input](./customize/build_graph/pipeline/kg_builder_from_pdf.py) - [Process multiple documents](./customize/build_graph/pipeline/kg_builder_two_documents_entity_resolution.py) - [Export lexical graph creation into another pipeline](./customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py) +- [Build pipeline from config file](customize/build_graph/pipeline/from_config_files/pipeline_from_config_file.py) #### Components diff --git a/examples/build_graph/from_config_files/simple_kg_pipeline_config.json b/examples/build_graph/from_config_files/simple_kg_pipeline_config.json new file mode 100644 index 00000000..ef251624 --- /dev/null +++ b/examples/build_graph/from_config_files/simple_kg_pipeline_config.json @@ -0,0 +1,112 @@ +{ + "version_": "1", + "template_": "SimpleKGPipeline", + "neo4j_config": { + "params_": { + "uri": { + "resolver_": "ENV", + "var_": "NEO4J_URI" + }, + "user": { + "resolver_": "ENV", + "var_": "NEO4J_USER" + }, + "password": { + "resolver_": "ENV", + "var_": "NEO4J_PASSWORD" + } + } + }, + "llm_config": { + "class_": "OpenAILLM", + "params_": { + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY" + }, + "model_name": "gpt-4o", + "model_params": { + "temperature": 0, + "max_tokens": 2000, + "response_format": {"type": "json_object"} + } + } + }, + "embedder_config": { + "class_": "OpenAIEmbeddings", + "params_": { + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY" + } + } + }, + "from_pdf": false, + "entities": [ + "Person", + { + "label": "House", + "description": "Family the person belongs to", + "properties": [ + { + "name": "name", + "type": "STRING" + } + ] + }, + { + "label": "Planet", + "properties": [ + { + "name": "name", + "type": "STRING" + }, + { + "name": "weather", + "type": "STRING" + } + ] + } + ], + "relations": [ + "PARENT_OF", + { + "label": "HEIR_OF", + "description": "Used for inheritor relationship between father and sons" + }, + { + "label": "RULES", + "properties": [ + { + "name": "fromYear", + "type": "INTEGER" + } + ] + } + ], + "potential_schema": [ + [ + "Person", + "PARENT_OF", + "Person" + ], + [ + "Person", + "HEIR_OF", + "House" + ], + [ + "House", + "RULES", + "Planet" + ] + ], + "text_splitter": { + "class_": "text_splitters.fixed_size_splitter.FixedSizeSplitter", + "params_": { + "chunk_size": 100, + "chunk_overlap": 10 + } + }, + "perform_entity_resolution": true +} diff --git a/examples/build_graph/from_config_files/simple_kg_pipeline_config.yaml b/examples/build_graph/from_config_files/simple_kg_pipeline_config.yaml new file mode 100644 index 00000000..8917e8ca --- /dev/null +++ b/examples/build_graph/from_config_files/simple_kg_pipeline_config.yaml @@ -0,0 +1,63 @@ +version_: "1" +template_: SimpleKGPipeline +neo4j_config: + params_: + uri: + resolver_: ENV + var_: NEO4J_URI + user: + resolver_: ENV + var_: NEO4J_USER + password: + resolver_: ENV + var_: NEO4J_PASSWORD +llm_config: + class_: OpenAILLM + params_: + api_key: + resolver_: ENV + var_: OPENAI_API_KEY + model_name: gpt-4o + model_params: + temperature: 0 + max_tokens: 2000 + response_format: + type: json_object +embedder_config: + class_: OpenAIEmbeddings + params_: + api_key: + resolver_: ENV + var_: OPENAI_API_KEY +from_pdf: false +entities: + - label: Person + - label: House + description: Family the person belongs to + properties: + - name: name + type: STRING + - label: Planet + properties: + - name: name + type: STRING + - name: weather + type: STRING +relations: + - label: PARENT_OF + - label: HEIR_OF + description: Used for inheritor relationship between father and sons + - label: RULES + properties: + - name: fromYear + type: INTEGER +potential_schema: + - ["Person", "PARENT_OF", "Person"] + - ["Person", "HEIR_OF", "House"] + - ["House", "RULES", "Planet"] +text_splitter: + class_: text_splitters.fixed_size_splitter.FixedSizeSplitter + params_: + chunk_size: 100 + chunk_overlap: 10 +perform_entity_resolution: true diff --git a/examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py b/examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py new file mode 100644 index 00000000..62ba6c85 --- /dev/null +++ b/examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py @@ -0,0 +1,47 @@ +"""In this example, the pipeline is defined in a JSON ('simple_kg_pipeline_config.json') +or YAML ('simple_kg_pipeline_config.yaml') file. + +According to the configuration file, some parameters will be read from the env vars +(Neo4j credentials and the OpenAI API key). +""" + +import asyncio +import logging + +## If env vars are in a .env file, uncomment: +## (requires pip install python-dotenv) +# from dotenv import load_dotenv +# load_dotenv() +# env vars manually set for testing: +import os +from pathlib import Path + +from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner +from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult + +logging.basicConfig() +logging.getLogger("neo4j_graphrag").setLevel(logging.DEBUG) + +os.environ["NEO4J_URI"] = "bolt://localhost:7687" +os.environ["NEO4J_USER"] = "neo4j" +os.environ["NEO4J_PASSWORD"] = "password" +# os.environ["OPENAI_API_KEY"] = "sk-..." + + +root_dir = Path(__file__).parent +file_path = root_dir / "simple_kg_pipeline_config.yaml" +# file_path = root_dir / "simple_kg_pipeline_config.json" + + +# Text to process +TEXT = """The son of Duke Leto Atreides and the Lady Jessica, Paul is the heir of House Atreides, +an aristocratic family that rules the planet Caladan, the rainy planet, since 10191.""" + + +async def main() -> PipelineResult: + pipeline = PipelineRunner.from_config_file(file_path) + return await pipeline.run({"text": TEXT}) + + +if __name__ == "__main__": + print(asyncio.run(main())) diff --git a/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.json b/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.json new file mode 100644 index 00000000..ce815412 --- /dev/null +++ b/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.json @@ -0,0 +1,68 @@ +{ + "version_": "1", + "template_": "none", + "name": "", + "neo4j_config": { + "params_": { + "uri": { + "resolver_": "ENV", + "var_": "NEO4J_URI" + }, + "user": { + "resolver_": "ENV", + "var_": "NEO4J_USER" + }, + "password": { + "resolver_": "ENV", + "var_": "NEO4J_PASSWORD" + } + } + }, + "extras": { + "database": "neo4j" + }, + "component_config": { + "splitter": { + "class_": "text_splitters.fixed_size_splitter.FixedSizeSplitter" + }, + "builder": { + "class_": "lexical_graph.LexicalGraphBuilder", + "params_": { + "config": { + "chunk_node_label": "TextPart" + } + } + }, + "writer": { + "name_": "writer", + "class_": "kg_writer.Neo4jWriter", + "params_": { + "driver": { + "resolver_": "CONFIG_KEY", + "key_": "neo4j_config.default" + }, + "neo4j_database": { + "resolver_": "CONFIG_KEY", + "key_": "extras.database" + } + } + } + }, + "connection_config": [ + { + "start": "splitter", + "end": "builder", + "input_config": { + "text_chunks": "splitter" + } + }, + { + "start": "builder", + "end": "writer", + "input_config": { + "graph": "builder.graph", + "lexical_graph_config": "builder.config" + } + } + ] +} diff --git a/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.yaml b/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.yaml new file mode 100644 index 00000000..87ac905e --- /dev/null +++ b/examples/customize/build_graph/pipeline/from_config_files/pipeline_config.yaml @@ -0,0 +1,45 @@ +version_: "1" +template_: none +neo4j_config: + params_: + uri: + resolver_: ENV + var_: NEO4J_URI + user: + resolver_: ENV + var_: NEO4J_USER + password: + resolver_: ENV + var_: NEO4J_PASSWORD +extras: + database: neo4j +component_config: + splitter: + class_: text_splitters.fixed_size_splitter.FixedSizeSplitter + params_: + chunk_size: 100 + chunk_overlap: 10 + builder: + class_: lexical_graph.LexicalGraphBuilder + params_: + config: + chunk_node_label: TextPart + writer: + class_: kg_writer.Neo4jWriter + params_: + driver: + resolver_: CONFIG_KEY + key_: neo4j_config.default + neo4j_database: + resolver_: CONFIG_KEY + key_: extras.database +connection_config: + - start: splitter + end: builder + input_config: + text_chunks: splitter + - start: builder + end: writer + input_config: + graph: builder.graph + lexical_graph_config: builder.config diff --git a/examples/customize/build_graph/pipeline/from_config_files/pipeline_from_config_file.py b/examples/customize/build_graph/pipeline/from_config_files/pipeline_from_config_file.py new file mode 100644 index 00000000..9a2a1680 --- /dev/null +++ b/examples/customize/build_graph/pipeline/from_config_files/pipeline_from_config_file.py @@ -0,0 +1,40 @@ +"""In this example, the pipeline is defined in a JSON file 'pipeline_config.json'. +According to the configuration file, some parameters will be read from the env vars +(Neo4j credentials and the OpenAI API key). +""" + +import asyncio + +## If env vars are in a .env file, uncomment: +## (requires pip install python-dotenv) +# from dotenv import load_dotenv +# load_dotenv() +# env vars manually set for testing: +import os +from pathlib import Path + +from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner +from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult + +os.environ["NEO4J_URI"] = "bolt://localhost:7687" +os.environ["NEO4J_USER"] = "neo4j" +os.environ["NEO4J_PASSWORD"] = "password" +# os.environ["OPENAI_API_KEY"] = "sk-..." + + +root_dir = Path(__file__).parent +# file_path = root_dir / "pipeline_config.json" +file_path = root_dir / "pipeline_config.yaml" + +# Text to process +TEXT = """The son of Duke Leto Atreides and the Lady Jessica, Paul is the heir of House Atreides, +an aristocratic family that rules the planet Caladan, the rainy planet, since 10191.""" + + +async def main() -> PipelineResult: + pipeline = PipelineRunner.from_config_file(file_path) + return await pipeline.run({"splitter": {"text": TEXT}}) + + +if __name__ == "__main__": + print(asyncio.run(main())) diff --git a/poetry.lock b/poetry.lock index e7bf3849..a662e717 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1905,18 +1905,18 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.23" +version = "0.3.24" description = "Building applications with LLMs through composability" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.23-py3-none-any.whl", hash = "sha256:550c0b996990830fa6515a71a1192a8a0343367999afc36d4ede14222941e420"}, - {file = "langchain_core-0.3.23.tar.gz", hash = "sha256:f9e175e3b82063cc3b160c2ca2b155832e1c6f915312e1204828f97d4aabf6e1"}, + {file = "langchain_core-0.3.24-py3-none-any.whl", hash = "sha256:97192552ef882a3dd6ae3b870a180a743801d0137a1159173f51ac555eeb7eec"}, + {file = "langchain_core-0.3.24.tar.gz", hash = "sha256:460851e8145327f70b70aad7dce2cdbd285e144d14af82b677256b941fc99656"}, ] [package.dependencies] jsonpatch = ">=1.33,<2.0" -langsmith = ">=0.1.125,<0.2.0" +langsmith = ">=0.1.125,<0.3" packaging = ">=23.2,<25" pydantic = [ {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, @@ -1976,13 +1976,13 @@ langchain-core = ">=0.3.15,<0.4.0" [[package]] name = "langsmith" -version = "0.1.147" +version = "0.2.2" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = true -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" files = [ - {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, - {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, + {file = "langsmith-0.2.2-py3-none-any.whl", hash = "sha256:4786d7dcdbc25e43d4a1bf70bbe12938a9eb2364feec8f6fc4d967162519b367"}, + {file = "langsmith-0.2.2.tar.gz", hash = "sha256:6f515ee41ae80968a7d552be1154414ccde57a0a534c960c8c3cd1835734095f"}, ] [package.dependencies] @@ -2866,13 +2866,13 @@ files = [ [[package]] name = "openai" -version = "1.57.1" +version = "1.57.2" description = "The official Python library for the openai API" optional = true python-versions = ">=3.8" files = [ - {file = "openai-1.57.1-py3-none-any.whl", hash = "sha256:3865686c927e93492d1145938d4a24b634951531c4b2769d43ca5dbd4b25d8fd"}, - {file = "openai-1.57.1.tar.gz", hash = "sha256:a95f22e04ab3df26e64a15d958342265e802314131275908b3b3e36f8c5d4377"}, + {file = "openai-1.57.2-py3-none-any.whl", hash = "sha256:f7326283c156fdee875746e7e54d36959fb198eadc683952ee05e3302fbd638d"}, + {file = "openai-1.57.2.tar.gz", hash = "sha256:5f49fd0f38e9f2131cda7deb45dafdd1aee4f52a637e190ce0ecf40147ce8cee"}, ] [package.dependencies] @@ -4928,6 +4928,17 @@ build = ["cmake (>=3.20)", "lit"] tests = ["autopep8", "flake8", "isort", "llnl-hatchet", "numpy", "pytest", "scipy (>=1.7.1)"] tutorials = ["matplotlib", "pandas", "tabulate"] +[[package]] +name = "types-pyyaml" +version = "6.0.12.20240917" +description = "Typing stubs for PyYAML" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"}, + {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"}, +] + [[package]] name = "types-requests" version = "2.31.0.6" @@ -5267,4 +5278,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = "^3.9.0" -content-hash = "eb706cb5d3d47a4d3ac32bc7f228bda27de77c87398999d1e610552ff19af93f" +content-hash = "5f729b5f7f31021258d04fcf26e2310f685f1b97113e888ba346df5c7393d4e4" diff --git a/pyproject.toml b/pyproject.toml index 6007709d..604fde99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ openai = {version = "^1.51.1", optional = true } anthropic = { version = "^0.36.0", optional = true} sentence-transformers = {version = "^3.0.0", optional = true } json-repair = "^0.30.2" +types-pyyaml = "^6.0.12.20240917" [tool.poetry.group.dev.dependencies] urllib3 = "<2" diff --git a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py b/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py index 225b4c0f..d4070aea 100644 --- a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py +++ b/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py @@ -23,7 +23,6 @@ from typing import Any, List, Optional, Union, cast import json_repair - from pydantic import ValidationError, validate_call from neo4j_graphrag.exceptions import LLMGenerationError diff --git a/src/neo4j_graphrag/experimental/components/lexical_graph.py b/src/neo4j_graphrag/experimental/components/lexical_graph.py index 92681a8b..ce96b9fd 100644 --- a/src/neo4j_graphrag/experimental/components/lexical_graph.py +++ b/src/neo4j_graphrag/experimental/components/lexical_graph.py @@ -42,6 +42,7 @@ class LexicalGraphBuilder(Component): - A relationship between a chunk and the next one in the document """ + @validate_call def __init__( self, config: LexicalGraphConfig = LexicalGraphConfig(), diff --git a/src/neo4j_graphrag/experimental/components/schema.py b/src/neo4j_graphrag/experimental/components/schema.py index 64e908ed..0f118545 100644 --- a/src/neo4j_graphrag/experimental/components/schema.py +++ b/src/neo4j_graphrag/experimental/components/schema.py @@ -17,9 +17,14 @@ from typing import Any, Dict, List, Literal, Optional, Tuple from pydantic import BaseModel, ValidationError, model_validator, validate_call +from typing_extensions import Self from neo4j_graphrag.exceptions import SchemaValidationError from neo4j_graphrag.experimental.pipeline.component import Component, DataModel +from neo4j_graphrag.experimental.pipeline.types import ( + EntityInputType, + RelationInputType, +) class SchemaProperty(BaseModel): @@ -55,6 +60,14 @@ class SchemaEntity(BaseModel): description: str = "" properties: List[SchemaProperty] = [] + @classmethod + def from_text_or_dict(cls, input: EntityInputType) -> Self: + if isinstance(input, SchemaEntity): + return input + if isinstance(input, str): + return cls(label=input) + return cls.model_validate(input) + class SchemaRelation(BaseModel): """ @@ -65,6 +78,14 @@ class SchemaRelation(BaseModel): description: str = "" properties: List[SchemaProperty] = [] + @classmethod + def from_text_or_dict(cls, input: RelationInputType) -> Self: + if isinstance(input, SchemaRelation): + return input + if isinstance(input, str): + return cls(label=input) + return cls.model_validate(input) + class SchemaConfig(DataModel): """ diff --git a/src/neo4j_graphrag/experimental/pipeline/config/__init__.py b/src/neo4j_graphrag/experimental/pipeline/config/__init__.py new file mode 100644 index 00000000..c0199c14 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/src/neo4j_graphrag/experimental/pipeline/config/base.py b/src/neo4j_graphrag/experimental/pipeline/config/base.py new file mode 100644 index 00000000..665a56d0 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/base.py @@ -0,0 +1,62 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Abstract class for all pipeline configs.""" + +from __future__ import annotations + +import logging +from typing import Any + +from pydantic import BaseModel, PrivateAttr + +from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( + ParamConfig, + ParamToResolveConfig, +) + +logger = logging.getLogger(__name__) + + +class AbstractConfig(BaseModel): + """Base class for all configs. + Provides methods to get a class from a string and resolve a parameter defined by + a dict with a 'resolver_' key. + + Each subclass must implement a 'parse' method that returns the relevant object. + """ + + _global_data: dict[str, Any] = PrivateAttr({}) + """Additional parameter ignored by all Pydantic model_* methods.""" + + def resolve_param(self, param: ParamConfig) -> Any: + """Finds the parameter value from its definition.""" + if not isinstance(param, ParamToResolveConfig): + # some parameters do not have to be resolved, real + # values are already provided + return param + return param.resolve(self._global_data) + + def resolve_params(self, params: dict[str, ParamConfig]) -> dict[str, Any]: + """Resolve all parameters + + Returning dict[str, Any] because parameters can be anything (str, float, list, dict...) + """ + return { + param_name: self.resolve_param(param) + for param_name, param in params.items() + } + + def parse(self, resolved_data: dict[str, Any] | None = None) -> Any: + raise NotImplementedError() diff --git a/src/neo4j_graphrag/experimental/pipeline/config/config_reader.py b/src/neo4j_graphrag/experimental/pipeline/config/config_reader.py new file mode 100644 index 00000000..c3df28d9 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/config_reader.py @@ -0,0 +1,85 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Read JSON or YAML files and returns a dict. +No data validation performed at this stage. +""" + +import json +import logging +from pathlib import Path +from typing import Any, Optional + +import fsspec +import yaml +from fsspec.implementations.local import LocalFileSystem + +logger = logging.getLogger(__name__) + + +class ConfigReader: + """Reads config from a file (JSON or YAML format) + and returns a dict. + + File format is guessed from the extension. Supported extensions are + (lower or upper case): + + - .json + - .yaml, .yml + + Example: + + .. code-block:: python + + from pathlib import Path + from neo4j_graphrag.experimental.pipeline.config.reader import ConfigReader + reader = ConfigReader() + reader.read(Path("my_file.json")) + + If reading a file with a different extension but still in JSON or YAML format, + it is possible to call directly the `read_json` or `read_yaml` methods: + + .. code-block:: python + + reader.read_yaml(Path("my_file.txt")) + + """ + + def __init__(self, fs: Optional[fsspec.AbstractFileSystem] = None) -> None: + self.fs = fs or LocalFileSystem() + + def read_json(self, file_path: str) -> Any: + logger.debug(f"CONFIG_READER: read from json {file_path}") + with self.fs.open(file_path, "r") as f: + return json.load(f) + + def read_yaml(self, file_path: str) -> Any: + logger.debug(f"CONFIG_READER: read from yaml {file_path}") + with self.fs.open(file_path, "r") as f: + return yaml.safe_load(f) + + def _guess_format_and_read(self, file_path: str) -> dict[str, Any]: + p = Path(file_path) + extension = p.suffix.lower() + # Note: .suffix returns an empty string if Path has no extension + # if not returning a dict, parsing will fail later on + if extension in [".json"]: + return self.read_json(file_path) # type: ignore[no-any-return] + if extension in [".yaml", ".yml"]: + return self.read_yaml(file_path) # type: ignore[no-any-return] + raise ValueError(f"Unsupported extension: {extension}") + + def read(self, file_path: str) -> dict[str, Any]: + data = self._guess_format_and_read(file_path) + return data diff --git a/src/neo4j_graphrag/experimental/pipeline/config/object_config.py b/src/neo4j_graphrag/experimental/pipeline/config/object_config.py new file mode 100644 index 00000000..cb47b380 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/object_config.py @@ -0,0 +1,266 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Config for all parameters that can be both provided as object instance or +config dict with 'class_' and 'params_' keys. + +Nomenclature in this file: + +- `*Config` models are used to represent "things" as dict to be used in a config file. + e.g.: + - neo4j.Driver => {"uri": "", "user": "", "password": ""} + - LLMInterface => {"class_": "OpenAI", "params_": {"model_name": "gpt-4o"}} +- `*Type` models are wrappers around an object and a 'Config' the object can be created + from. They are used to allow the instantiation of "PipelineConfig" either from + instantiated objects (when used in code) and from a config dict (when used to + load config from file). +""" + +from __future__ import annotations + +import importlib +import logging +from typing import ( + Any, + ClassVar, + Generic, + Optional, + TypeVar, + Union, + cast, +) + +import neo4j +from pydantic import ( + ConfigDict, + Field, + RootModel, + field_validator, +) + +from neo4j_graphrag.embeddings import Embedder +from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.experimental.pipeline.config.base import AbstractConfig +from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( + ParamConfig, +) +from neo4j_graphrag.llm import LLMInterface + +logger = logging.getLogger(__name__) + + +T = TypeVar("T") +"""Generic type to help mypy with the parse method when we know the exact +expected return type (e.g. for the Neo4jDriverConfig below). +""" + + +class ObjectConfig(AbstractConfig, Generic[T]): + """A config class to represent an object from a class name + and its constructor parameters. + """ + + class_: str | None = Field(default=None, validate_default=True) + """Path to class to be instantiated.""" + params_: dict[str, ParamConfig] = {} + """Initialization parameters.""" + + DEFAULT_MODULE: ClassVar[str] = "." + """Default module to import the class from.""" + INTERFACE: ClassVar[type] = object + """Constraint on the class (must be a subclass of).""" + REQUIRED_PARAMS: ClassVar[list[str]] = [] + """List of required parameters for this object constructor.""" + + @field_validator("params_") + @classmethod + def validate_params(cls, params_: dict[str, Any]) -> dict[str, Any]: + """Make sure all required parameters are provided.""" + for p in cls.REQUIRED_PARAMS: + if p not in params_: + raise ValueError(f"Missing parameter {p}") + return params_ + + def get_module(self) -> str: + return self.DEFAULT_MODULE + + def get_interface(self) -> type: + return self.INTERFACE + + @classmethod + def _get_class(cls, class_path: str, optional_module: Optional[str] = None) -> type: + """Get class from string and an optional module + + Will first try to import the class from `class_path` alone. If it results in an ImportError, + will try to import from `f'{optional_module}.{class_path}'` + + Args: + class_path (str): Class path with format 'my_module.MyClass'. + optional_module (Optional[str]): Optional module path. Used to provide a default path for some known objects and simplify the notation. + + Raises: + ValueError: if the class can't be imported, even using the optional module. + """ + *modules, class_name = class_path.rsplit(".", 1) + module_name = modules[0] if modules else optional_module + if module_name is None: + raise ValueError("Must specify a module to import class from") + try: + module = importlib.import_module(module_name) + klass = getattr(module, class_name) + except (ImportError, AttributeError): + if optional_module and module_name != optional_module: + full_klass_path = optional_module + "." + class_path + return cls._get_class(full_klass_path) + raise ValueError(f"Could not find {class_name} in {module_name}") + return cast(type, klass) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> T: + """Import `class_`, resolve `params_` and instantiate object.""" + self._global_data = resolved_data or {} + logger.debug(f"OBJECT_CONFIG: parsing {self} using {resolved_data}") + if self.class_ is None: + raise ValueError(f"`class_` is not required to parse object {self}") + klass = self._get_class(self.class_, self.get_module()) + if not issubclass(klass, self.get_interface()): + raise ValueError( + f"Invalid class '{klass}'. Expected a subclass of '{self.get_interface()}'" + ) + params = self.resolve_params(self.params_) + try: + obj = klass(**params) + except TypeError as e: + logger.error( + "OBJECT_CONFIG: failed to instantiate object due to improperly configured parameters" + ) + raise e + return cast(T, obj) + + +class Neo4jDriverConfig(ObjectConfig[neo4j.Driver]): + REQUIRED_PARAMS = ["uri", "user", "password"] + + @field_validator("class_", mode="before") + @classmethod + def validate_class(cls, class_: Any) -> str: + """`class_` parameter is not used because we're always using the sync driver.""" + if class_: + logger.info("Parameter class_ is not used for Neo4jDriverConfig") + # not used + return "not used" + + def parse(self, resolved_data: dict[str, Any] | None = None) -> neo4j.Driver: + params = self.resolve_params(self.params_) + # we know these params are there because of the required params validator + uri = params.pop("uri") + user = params.pop("user") + password = params.pop("password") + driver = neo4j.GraphDatabase.driver(uri, auth=(user, password), **params) + return driver + + +# note: using the notation with RootModel + root: field +# instead of RootModel[] for clarity +# but this requires the type: ignore comment below +class Neo4jDriverType(RootModel): # type: ignore[type-arg] + """A model to wrap neo4j.Driver and Neo4jDriverConfig objects. + + The `parse` method always returns a neo4j.Driver. + """ + + root: Union[neo4j.Driver, Neo4jDriverConfig] + + model_config = ConfigDict(arbitrary_types_allowed=True) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> neo4j.Driver: + if isinstance(self.root, neo4j.Driver): + return self.root + # self.root is a Neo4jDriverConfig object + return self.root.parse(resolved_data) + + +class LLMConfig(ObjectConfig[LLMInterface]): + """Configuration for any LLMInterface object. + + By default, will try to import from `neo4j_graphrag.llm`. + """ + + DEFAULT_MODULE = "neo4j_graphrag.llm" + INTERFACE = LLMInterface + + +class LLMType(RootModel): # type: ignore[type-arg] + """A model to wrap LLMInterface and LLMConfig objects. + + The `parse` method always returns an object inheriting from LLMInterface. + """ + + root: Union[LLMInterface, LLMConfig] + + model_config = ConfigDict(arbitrary_types_allowed=True) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> LLMInterface: + if isinstance(self.root, LLMInterface): + return self.root + return self.root.parse(resolved_data) + + +class EmbedderConfig(ObjectConfig[Embedder]): + """Configuration for any Embedder object. + + By default, will try to import from `neo4j_graphrag.embeddings`. + """ + + DEFAULT_MODULE = "neo4j_graphrag.embeddings" + INTERFACE = Embedder + + +class EmbedderType(RootModel): # type: ignore[type-arg] + """A model to wrap Embedder and EmbedderConfig objects. + + The `parse` method always returns an object inheriting from Embedder. + """ + + root: Union[Embedder, EmbedderConfig] + + model_config = ConfigDict(arbitrary_types_allowed=True) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> Embedder: + if isinstance(self.root, Embedder): + return self.root + return self.root.parse(resolved_data) + + +class ComponentConfig(ObjectConfig[Component]): + """A config model for all components. + + In addition to the object config, components can have pre-defined parameters + that will be passed to the `run` method, ie `run_params_`. + """ + + run_params_: dict[str, ParamConfig] = {} + + DEFAULT_MODULE = "neo4j_graphrag.experimental.components" + INTERFACE = Component + + +class ComponentType(RootModel): # type: ignore[type-arg] + root: Union[Component, ComponentConfig] + + model_config = ConfigDict(arbitrary_types_allowed=True) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> Component: + if isinstance(self.root, Component): + return self.root + return self.root.parse(resolved_data) diff --git a/src/neo4j_graphrag/experimental/pipeline/config/param_resolver.py b/src/neo4j_graphrag/experimental/pipeline/config/param_resolver.py new file mode 100644 index 00000000..24190add --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/param_resolver.py @@ -0,0 +1,60 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import enum +import os +from typing import Any, ClassVar, Literal, Union + +from pydantic import BaseModel + + +class ParamResolverEnum(str, enum.Enum): + ENV = "ENV" + CONFIG_KEY = "CONFIG_KEY" + + +class ParamToResolveConfig(BaseModel): + def resolve(self, data: dict[str, Any]) -> Any: + raise NotImplementedError + + +class ParamFromEnvConfig(ParamToResolveConfig): + resolver_: Literal[ParamResolverEnum.ENV] = ParamResolverEnum.ENV + var_: str + + def resolve(self, data: dict[str, Any]) -> Any: + return os.environ.get(self.var_) + + +class ParamFromKeyConfig(ParamToResolveConfig): + resolver_: Literal[ParamResolverEnum.CONFIG_KEY] = ParamResolverEnum.CONFIG_KEY + key_: str + + KEY_SEP: ClassVar[str] = "." + + def resolve(self, data: dict[str, Any]) -> Any: + d = data + for k in self.key_.split(self.KEY_SEP): + d = d[k] + return d + + +ParamConfig = Union[ + float, + str, + ParamFromEnvConfig, + ParamFromKeyConfig, + dict[str, Any], +] diff --git a/src/neo4j_graphrag/experimental/pipeline/config/pipeline_config.py b/src/neo4j_graphrag/experimental/pipeline/config/pipeline_config.py new file mode 100644 index 00000000..c3871179 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/pipeline_config.py @@ -0,0 +1,199 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from typing import Any, ClassVar, Literal, Optional, Union + +import neo4j +from pydantic import field_validator + +from neo4j_graphrag.embeddings import Embedder +from neo4j_graphrag.experimental.pipeline.config.base import AbstractConfig +from neo4j_graphrag.experimental.pipeline.config.object_config import ( + ComponentType, + EmbedderType, + LLMType, + Neo4jDriverType, +) +from neo4j_graphrag.experimental.pipeline.config.types import PipelineType +from neo4j_graphrag.experimental.pipeline.types import ( + ComponentDefinition, + ConnectionDefinition, + PipelineDefinition, +) +from neo4j_graphrag.llm import LLMInterface + +logger = logging.getLogger(__name__) + + +class AbstractPipelineConfig(AbstractConfig): + """This class defines the fields possibly used by all pipelines: neo4j drivers, LLMs... + neo4j_config, llm_config can be provided by user as a single item or a dict of items. + Validators deal with type conversion so that the field in all instances is a dict of items. + """ + + neo4j_config: dict[str, Neo4jDriverType] = {} + llm_config: dict[str, LLMType] = {} + embedder_config: dict[str, EmbedderType] = {} + # extra parameters values that can be used in different places of the config file + extras: dict[str, Any] = {} + + DEFAULT_NAME: ClassVar[str] = "default" + """Name of the default item in dict + """ + + @field_validator("neo4j_config", mode="before") + @classmethod + def validate_drivers( + cls, drivers: Union[Neo4jDriverType, dict[str, Any]] + ) -> dict[str, Any]: + if not isinstance(drivers, dict) or "params_" in drivers: + return {cls.DEFAULT_NAME: drivers} + return drivers + + @field_validator("llm_config", mode="before") + @classmethod + def validate_llms(cls, llms: Union[LLMType, dict[str, Any]]) -> dict[str, Any]: + if not isinstance(llms, dict) or "class_" in llms: + return {cls.DEFAULT_NAME: llms} + return llms + + @field_validator("embedder_config", mode="before") + @classmethod + def validate_embedders( + cls, embedders: Union[EmbedderType, dict[str, Any]] + ) -> dict[str, Any]: + if not isinstance(embedders, dict) or "class_" in embedders: + return {cls.DEFAULT_NAME: embedders} + return embedders + + def _resolve_component_definition( + self, name: str, config: ComponentType + ) -> ComponentDefinition: + component = config.parse(self._global_data) + if hasattr(config.root, "run_params_"): + component_run_params = self.resolve_params(config.root.run_params_) + else: + component_run_params = {} + component_def = ComponentDefinition( + name=name, + component=component, + run_params=component_run_params, + ) + logger.debug(f"PIPELINE_CONFIG: resolved component {component_def}") + return component_def + + def _parse_global_data(self) -> dict[str, Any]: + """Global data contains data that can be referenced in other parts of the + config. + + Typically, neo4j drivers, LLMs and embedders can be referenced in component + input parameters. + """ + # 'extras' parameters can be referenced in other configs, + # that's why they are parsed before the others + # e.g., an API key used for both LLM and Embedder can be stored only + # once in extras. + extra_data = { + "extras": self.resolve_params(self.extras), + } + logger.debug(f"PIPELINE_CONFIG: resolved 'extras': {extra_data}") + drivers: dict[str, neo4j.Driver] = { + driver_name: driver_config.parse(extra_data) + for driver_name, driver_config in self.neo4j_config.items() + } + llms: dict[str, LLMInterface] = { + llm_name: llm_config.parse(extra_data) + for llm_name, llm_config in self.llm_config.items() + } + embedders: dict[str, Embedder] = { + embedder_name: embedder_config.parse(extra_data) + for embedder_name, embedder_config in self.embedder_config.items() + } + global_data = { + **extra_data, + "neo4j_config": drivers, + "llm_config": llms, + "embedder_config": embedders, + } + logger.debug(f"PIPELINE_CONFIG: resolved globals: {global_data}") + return global_data + + def _get_components(self) -> list[ComponentDefinition]: + return [] + + def _get_connections(self) -> list[ConnectionDefinition]: + return [] + + def parse( + self, resolved_data: Optional[dict[str, Any]] = None + ) -> PipelineDefinition: + """Parse the full config and returns a PipelineDefinition object, containing instantiated + components and a list of connections. + """ + self._global_data = self._parse_global_data() + return PipelineDefinition( + components=self._get_components(), + connections=self._get_connections(), + ) + + def get_run_params(self, user_input: dict[str, Any]) -> dict[str, Any]: + return user_input + + async def close(self) -> None: + drivers = self._global_data.get("neo4j_config", {}) + for driver_name in drivers: + driver = drivers[driver_name] + logger.debug(f"PIPELINE_CONFIG: closing driver {driver_name}: {driver}") + driver.close() + + def get_neo4j_driver_by_name(self, name: str) -> neo4j.Driver: + drivers: dict[str, neo4j.Driver] = self._global_data.get("neo4j_config", {}) + return drivers[name] + + def get_default_neo4j_driver(self) -> neo4j.Driver: + return self.get_neo4j_driver_by_name(self.DEFAULT_NAME) + + def get_llm_by_name(self, name: str) -> LLMInterface: + llms: dict[str, LLMInterface] = self._global_data.get("llm_config", {}) + return llms[name] + + def get_default_llm(self) -> LLMInterface: + return self.get_llm_by_name(self.DEFAULT_NAME) + + def get_embedder_by_name(self, name: str) -> Embedder: + embedders: dict[str, Embedder] = self._global_data.get("embedder_config", {}) + return embedders[name] + + def get_default_embedder(self) -> Embedder: + return self.get_embedder_by_name(self.DEFAULT_NAME) + + +class PipelineConfig(AbstractPipelineConfig): + """Configuration class for raw pipelines. + Config must contain all components and connections.""" + + component_config: dict[str, ComponentType] + connection_config: list[ConnectionDefinition] + template_: Literal[PipelineType.NONE] = PipelineType.NONE + + def _get_connections(self) -> list[ConnectionDefinition]: + return self.connection_config + + def _get_components(self) -> list[ComponentDefinition]: + return [ + self._resolve_component_definition(name, component_config) + for name, component_config in self.component_config.items() + ] diff --git a/src/neo4j_graphrag/experimental/pipeline/config/runner.py b/src/neo4j_graphrag/experimental/pipeline/config/runner.py new file mode 100644 index 00000000..a1a22585 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/runner.py @@ -0,0 +1,132 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Pipeline config wrapper (router based on 'template_' key) +and pipeline runner. +""" + +from __future__ import annotations + +import logging +from pathlib import Path +from typing import ( + Annotated, + Any, + Union, +) + +from pydantic import ( + BaseModel, + Discriminator, + Field, + Tag, +) +from pydantic.v1.utils import deep_update +from typing_extensions import Self + +from neo4j_graphrag.experimental.pipeline import Pipeline +from neo4j_graphrag.experimental.pipeline.config.config_reader import ConfigReader +from neo4j_graphrag.experimental.pipeline.config.pipeline_config import ( + AbstractPipelineConfig, + PipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.config.template_pipeline.simple_kg_builder import ( + SimpleKGPipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.config.types import PipelineType +from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult +from neo4j_graphrag.experimental.pipeline.types import PipelineDefinition + +logger = logging.getLogger(__name__) + + +def _get_discriminator_value(model: Any) -> PipelineType: + template_ = None + if "template_" in model: + template_ = model["template_"] + if hasattr(model, "template_"): + template_ = model.template_ + return PipelineType(template_) or PipelineType.NONE + + +class PipelineConfigWrapper(BaseModel): + """The pipeline config wrapper will parse the right pipeline config based on the `template_` field.""" + + config: Union[ + Annotated[PipelineConfig, Tag(PipelineType.NONE)], + Annotated[SimpleKGPipelineConfig, Tag(PipelineType.SIMPLE_KG_PIPELINE)], + ] = Field(discriminator=Discriminator(_get_discriminator_value)) + + def parse(self, resolved_data: dict[str, Any] | None = None) -> PipelineDefinition: + return self.config.parse(resolved_data) + + def get_run_params(self, user_input: dict[str, Any]) -> dict[str, Any]: + return self.config.get_run_params(user_input) + + +class PipelineRunner: + """Pipeline runner builds a pipeline from different objects and exposes a run method to run pipeline + + Pipeline can be built from: + - A PipelineDefinition (`__init__` method) + - A PipelineConfig (`from_config` method) + - A config file (`from_config_file` method) + """ + + def __init__( + self, + pipeline_definition: PipelineDefinition, + config: AbstractPipelineConfig | None = None, + do_cleaning: bool = False, + ) -> None: + self.config = config + self.pipeline = Pipeline.from_definition(pipeline_definition) + self.run_params = pipeline_definition.get_run_params() + self.do_cleaning = do_cleaning + + @classmethod + def from_config( + cls, config: AbstractPipelineConfig | dict[str, Any], do_cleaning: bool = False + ) -> Self: + wrapper = PipelineConfigWrapper.model_validate({"config": config}) + return cls(wrapper.parse(), config=wrapper.config, do_cleaning=do_cleaning) + + @classmethod + def from_config_file(cls, file_path: Union[str, Path]) -> Self: + if not isinstance(file_path, str): + file_path = str(file_path) + data = ConfigReader().read(file_path) + return cls.from_config(data, do_cleaning=True) + + async def run(self, user_input: dict[str, Any]) -> PipelineResult: + # pipeline_conditional_run_params = self. + if self.config: + run_param = deep_update( + self.run_params, self.config.get_run_params(user_input) + ) + else: + run_param = deep_update(self.run_params, user_input) + logger.info( + f"PIPELINE_RUNNER: starting pipeline {self.pipeline} with run_params={run_param}" + ) + result = await self.pipeline.run(data=run_param) + if self.do_cleaning: + await self.close() + return result + + async def close(self) -> None: + logger.debug("PIPELINE_RUNNER: cleaning up (closing instantiated drivers...)") + if self.config: + await self.config.close() diff --git a/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/__init__.py b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/__init__.py new file mode 100644 index 00000000..125a1c87 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .simple_kg_builder import SimpleKGPipelineConfig + +__all__ = [ + "SimpleKGPipelineConfig", +] diff --git a/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/base.py b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/base.py new file mode 100644 index 00000000..69fbc751 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/base.py @@ -0,0 +1,63 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +from typing import Any, ClassVar, Optional + +from neo4j_graphrag.experimental.pipeline.config.pipeline_config import ( + AbstractPipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.types import ComponentDefinition + +logger = logging.getLogger(__name__) + + +class TemplatePipelineConfig(AbstractPipelineConfig): + """This class represent a 'template' pipeline, ie pipeline with pre-defined default + components and fixed connections. + + Component names are defined in the COMPONENTS class var. For each of them, + a `_get_` method must be implemented that returns the proper + component. Optionally, `_get_run_params_for_` can be implemented + to deal with parameters required by the component's run method and predefined on + template initialization. + """ + + COMPONENTS: ClassVar[list[str]] = [] + + def _get_component(self, component_name: str) -> Optional[ComponentDefinition]: + method = getattr(self, f"_get_{component_name}") + component = method() + if component is None: + return None + method = getattr(self, f"_get_run_params_for_{component_name}", None) + run_params = method() if method else {} + component_definition = ComponentDefinition( + name=component_name, + component=component, + run_params=run_params, + ) + logger.debug(f"TEMPLATE_PIPELINE: resolved component {component_definition}") + return component_definition + + def _get_components(self) -> list[ComponentDefinition]: + components = [] + for component_name in self.COMPONENTS: + comp = self._get_component(component_name) + if comp is not None: + components.append(comp) + return components + + def get_run_params(self, user_input: dict[str, Any]) -> dict[str, Any]: + return {} diff --git a/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py new file mode 100644 index 00000000..73edfd9a --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py @@ -0,0 +1,228 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Any, ClassVar, Literal, Optional, Sequence, Union + +from pydantic import ConfigDict + +from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder +from neo4j_graphrag.experimental.components.entity_relation_extractor import ( + EntityRelationExtractor, + LLMEntityRelationExtractor, + OnError, +) +from neo4j_graphrag.experimental.components.kg_writer import KGWriter, Neo4jWriter +from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader +from neo4j_graphrag.experimental.components.resolver import ( + EntityResolver, + SinglePropertyExactMatchResolver, +) +from neo4j_graphrag.experimental.components.schema import ( + SchemaBuilder, + SchemaEntity, + SchemaRelation, +) +from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter +from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) +from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.experimental.pipeline.config.object_config import ComponentType +from neo4j_graphrag.experimental.pipeline.config.template_pipeline.base import ( + TemplatePipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.config.types import PipelineType +from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError +from neo4j_graphrag.experimental.pipeline.types import ( + ConnectionDefinition, + EntityInputType, + RelationInputType, +) +from neo4j_graphrag.generation.prompts import ERExtractionTemplate + + +class SimpleKGPipelineConfig(TemplatePipelineConfig): + COMPONENTS: ClassVar[list[str]] = [ + "pdf_loader", + "splitter", + "chunk_embedder", + "schema", + "extractor", + "writer", + "resolver", + ] + + template_: Literal[PipelineType.SIMPLE_KG_PIPELINE] = ( + PipelineType.SIMPLE_KG_PIPELINE + ) + + from_pdf: bool = False + entities: Sequence[EntityInputType] = [] + relations: Sequence[RelationInputType] = [] + potential_schema: Optional[list[tuple[str, str, str]]] = None + on_error: OnError = OnError.IGNORE + prompt_template: Union[ERExtractionTemplate, str] = ERExtractionTemplate() + perform_entity_resolution: bool = True + lexical_graph_config: Optional[LexicalGraphConfig] = None + neo4j_database: Optional[str] = None + + pdf_loader: Optional[ComponentType] = None + kg_writer: Optional[ComponentType] = None + text_splitter: Optional[ComponentType] = None + + model_config = ConfigDict(arbitrary_types_allowed=True) + + def _get_pdf_loader(self) -> Optional[PdfLoader]: + if not self.from_pdf: + return None + if self.pdf_loader: + return self.pdf_loader.parse(self._global_data) # type: ignore + return PdfLoader() + + def _get_splitter(self) -> TextSplitter: + if self.text_splitter: + return self.text_splitter.parse(self._global_data) # type: ignore + return FixedSizeSplitter() + + def _get_chunk_embedder(self) -> TextChunkEmbedder: + return TextChunkEmbedder(embedder=self.get_default_embedder()) + + def _get_schema(self) -> SchemaBuilder: + return SchemaBuilder() + + def _get_run_params_for_schema(self) -> dict[str, Any]: + return { + "entities": [SchemaEntity.from_text_or_dict(e) for e in self.entities], + "relations": [SchemaRelation.from_text_or_dict(r) for r in self.relations], + "potential_schema": self.potential_schema, + } + + def _get_extractor(self) -> EntityRelationExtractor: + return LLMEntityRelationExtractor( + llm=self.get_default_llm(), + prompt_template=self.prompt_template, + on_error=self.on_error, + ) + + def _get_writer(self) -> KGWriter: + if self.kg_writer: + return self.kg_writer.parse(self._global_data) # type: ignore + return Neo4jWriter( + driver=self.get_default_neo4j_driver(), + neo4j_database=self.neo4j_database, + ) + + def _get_resolver(self) -> Optional[EntityResolver]: + if not self.perform_entity_resolution: + return None + return SinglePropertyExactMatchResolver( + driver=self.get_default_neo4j_driver(), + neo4j_database=self.neo4j_database, + ) + + def _get_connections(self) -> list[ConnectionDefinition]: + connections = [] + if self.from_pdf: + connections.append( + ConnectionDefinition( + start="pdf_loader", + end="splitter", + input_config={"text": "pdf_loader.text"}, + ) + ) + connections.append( + ConnectionDefinition( + start="schema", + end="extractor", + input_config={ + "schema": "schema", + "document_info": "pdf_loader.document_info", + }, + ) + ) + else: + connections.append( + ConnectionDefinition( + start="schema", + end="extractor", + input_config={ + "schema": "schema", + }, + ) + ) + connections.append( + ConnectionDefinition( + start="splitter", + end="chunk_embedder", + input_config={ + "text_chunks": "splitter", + }, + ) + ) + connections.append( + ConnectionDefinition( + start="chunk_embedder", + end="extractor", + input_config={ + "chunks": "chunk_embedder", + }, + ) + ) + connections.append( + ConnectionDefinition( + start="extractor", + end="writer", + input_config={ + "graph": "extractor", + }, + ) + ) + + if self.perform_entity_resolution: + connections.append( + ConnectionDefinition( + start="writer", + end="resolver", + input_config={}, + ) + ) + + return connections + + def get_run_params(self, user_input: dict[str, Any]) -> dict[str, Any]: + run_params = {} + if self.lexical_graph_config: + run_params["extractor"] = { + "lexical_graph_config": self.lexical_graph_config + } + text = user_input.get("text") + file_path = user_input.get("file_path") + if not ((text is None) ^ (file_path is None)): + # exactly one of text or user_input must be set + raise PipelineDefinitionError( + "Use either 'text' (when from_pdf=False) or 'file_path' (when from_pdf=True) argument." + ) + if self.from_pdf: + if not file_path: + raise PipelineDefinitionError( + "Expected 'file_path' argument when 'from_pdf' is True." + ) + run_params["pdf_loader"] = {"filepath": file_path} + else: + if not text: + raise PipelineDefinitionError( + "Expected 'text' argument when 'from_pdf' is False." + ) + run_params["splitter"] = {"text": text} + return run_params diff --git a/src/neo4j_graphrag/experimental/pipeline/config/types.py b/src/neo4j_graphrag/experimental/pipeline/config/types.py new file mode 100644 index 00000000..48f91f48 --- /dev/null +++ b/src/neo4j_graphrag/experimental/pipeline/config/types.py @@ -0,0 +1,26 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import enum + + +class PipelineType(str, enum.Enum): + """Pipeline type: + + NONE => Pipeline + SIMPLE_KG_PIPELINE ~> SimpleKGPipeline + """ + + NONE = "none" + SIMPLE_KG_PIPELINE = "SimpleKGPipeline" diff --git a/src/neo4j_graphrag/experimental/pipeline/kg_builder.py b/src/neo4j_graphrag/experimental/pipeline/kg_builder.py index 58868cb3..3fca0215 100644 --- a/src/neo4j_graphrag/experimental/pipeline/kg_builder.py +++ b/src/neo4j_graphrag/experimental/pipeline/kg_builder.py @@ -18,30 +18,16 @@ from typing import Any, List, Optional, Sequence, Union import neo4j -from pydantic import BaseModel, ConfigDict, Field +from pydantic import ValidationError from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, - OnError, -) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader -from neo4j_graphrag.experimental.components.resolver import ( - SinglePropertyExactMatchResolver, -) -from neo4j_graphrag.experimental.components.schema import ( - SchemaBuilder, - SchemaEntity, - SchemaRelation, -) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner +from neo4j_graphrag.experimental.pipeline.config.template_pipeline import ( + SimpleKGPipelineConfig, +) from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError -from neo4j_graphrag.experimental.pipeline.pipeline import Pipeline, PipelineResult +from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.experimental.pipeline.types import ( EntityInputType, RelationInputType, @@ -50,26 +36,6 @@ from neo4j_graphrag.llm.base import LLMInterface -class SimpleKGPipelineConfig(BaseModel): - llm: LLMInterface - driver: neo4j.Driver - from_pdf: bool - embedder: Embedder - entities: list[SchemaEntity] = Field(default_factory=list) - relations: list[SchemaRelation] = Field(default_factory=list) - potential_schema: list[tuple[str, str, str]] = Field(default_factory=list) - pdf_loader: Any = None - kg_writer: Any = None - text_splitter: Any = None - on_error: OnError = OnError.RAISE - prompt_template: Union[ERExtractionTemplate, str] = ERExtractionTemplate() - perform_entity_resolution: bool = True - lexical_graph_config: Optional[LexicalGraphConfig] = None - neo4j_database: Optional[str] = None - - model_config = ConfigDict(arbitrary_types_allowed=True) - - class SimpleKGPipeline: """ A class to simplify the process of building a knowledge graph from text documents. @@ -120,133 +86,29 @@ def __init__( lexical_graph_config: Optional[LexicalGraphConfig] = None, neo4j_database: Optional[str] = None, ): - self.potential_schema = potential_schema or [] - self.entities = [self.to_schema_entity(e) for e in entities or []] - self.relations = [self.to_schema_relation(r) for r in relations or []] - try: - on_error_enum = OnError(on_error) - except ValueError: - raise PipelineDefinitionError( - f"Invalid value for on_error: {on_error}. Expected one of {OnError.possible_values()}." - ) - - config = SimpleKGPipelineConfig( - llm=llm, - driver=driver, - entities=self.entities, - relations=self.relations, - potential_schema=self.potential_schema, - from_pdf=from_pdf, - pdf_loader=pdf_loader, - kg_writer=kg_writer, - text_splitter=text_splitter, - on_error=on_error_enum, - prompt_template=prompt_template, - embedder=embedder, - perform_entity_resolution=perform_entity_resolution, - lexical_graph_config=lexical_graph_config, - neo4j_database=neo4j_database, - ) - - self.from_pdf = config.from_pdf - self.llm = config.llm - self.driver = config.driver - self.embedder = config.embedder - self.text_splitter = config.text_splitter or FixedSizeSplitter() - self.on_error = config.on_error - self.pdf_loader = config.pdf_loader if pdf_loader is not None else PdfLoader() - self.kg_writer = ( - config.kg_writer - if kg_writer is not None - else Neo4jWriter(driver, neo4j_database=config.neo4j_database) - ) - self.prompt_template = config.prompt_template - self.perform_entity_resolution = config.perform_entity_resolution - self.lexical_graph_config = config.lexical_graph_config - self.neo4j_database = config.neo4j_database - - self.pipeline = self._build_pipeline() - - @staticmethod - def to_schema_entity(entity: EntityInputType) -> SchemaEntity: - if isinstance(entity, dict): - return SchemaEntity.model_validate(entity) - return SchemaEntity(label=entity) - - @staticmethod - def to_schema_relation(relation: RelationInputType) -> SchemaRelation: - if isinstance(relation, dict): - return SchemaRelation.model_validate(relation) - return SchemaRelation(label=relation) - - def _build_pipeline(self) -> Pipeline: - pipe = Pipeline() - - pipe.add_component(self.text_splitter, "splitter") - pipe.add_component(SchemaBuilder(), "schema") - pipe.add_component( - LLMEntityRelationExtractor( - llm=self.llm, - on_error=self.on_error, - prompt_template=self.prompt_template, - ), - "extractor", - ) - pipe.add_component(TextChunkEmbedder(embedder=self.embedder), "chunk_embedder") - pipe.add_component(self.kg_writer, "writer") - - if self.from_pdf: - pipe.add_component(self.pdf_loader, "pdf_loader") - - pipe.connect( - "pdf_loader", - "splitter", - input_config={"text": "pdf_loader.text"}, - ) - - pipe.connect( - "schema", - "extractor", - input_config={ - "schema": "schema", - "document_info": "pdf_loader.document_info", - }, - ) - else: - pipe.connect( - "schema", - "extractor", - input_config={ - "schema": "schema", - }, - ) - - pipe.connect( - "splitter", "chunk_embedder", input_config={"text_chunks": "splitter"} - ) - - pipe.connect( - "chunk_embedder", "extractor", input_config={"chunks": "chunk_embedder"} - ) - - # Connect extractor to writer - pipe.connect( - "extractor", - "writer", - input_config={"graph": "extractor"}, - ) - - if self.perform_entity_resolution: - pipe.add_component( - SinglePropertyExactMatchResolver( - self.driver, neo4j_database=self.neo4j_database - ), - "resolver", + config = SimpleKGPipelineConfig( + # argument type are fixed in the Config object + llm_config=llm, # type: ignore[arg-type] + neo4j_config=driver, # type: ignore[arg-type] + embedder_config=embedder, # type: ignore[arg-type] + entities=entities or [], + relations=relations or [], + potential_schema=potential_schema, + from_pdf=from_pdf, + pdf_loader=pdf_loader, + kg_writer=kg_writer, + text_splitter=text_splitter, + on_error=on_error, # type: ignore[arg-type] + prompt_template=prompt_template, + perform_entity_resolution=perform_entity_resolution, + lexical_graph_config=lexical_graph_config, + neo4j_database=neo4j_database, ) - pipe.connect("writer", "resolver", {}) + except ValidationError as e: + raise PipelineDefinitionError() from e - return pipe + self.runner = PipelineRunner.from_config(config) async def run_async( self, file_path: Optional[str] = None, text: Optional[str] = None @@ -261,39 +123,4 @@ async def run_async( Returns: PipelineResult: The result of the pipeline execution. """ - pipe_inputs = self._prepare_inputs(file_path=file_path, text=text) - return await self.pipeline.run(pipe_inputs) - - def _prepare_inputs( - self, file_path: Optional[str], text: Optional[str] - ) -> dict[str, Any]: - if self.from_pdf: - if file_path is None or text is not None: - raise PipelineDefinitionError( - "Expected 'file_path' argument when 'from_pdf' is True." - ) - else: - if text is None or file_path is not None: - raise PipelineDefinitionError( - "Expected 'text' argument when 'from_pdf' is False." - ) - - pipe_inputs: dict[str, Any] = { - "schema": { - "entities": self.entities, - "relations": self.relations, - "potential_schema": self.potential_schema, - }, - } - - if self.from_pdf: - pipe_inputs["pdf_loader"] = {"filepath": file_path} - else: - pipe_inputs["splitter"] = {"text": text} - - if self.lexical_graph_config: - pipe_inputs["extractor"] = { - "lexical_graph_config": self.lexical_graph_config - } - - return pipe_inputs + return await self.runner.run({"file_path": file_path, "text": text}) diff --git a/src/neo4j_graphrag/experimental/pipeline/pipeline.py b/src/neo4j_graphrag/experimental/pipeline/pipeline.py index 5edc2783..e3ded494 100644 --- a/src/neo4j_graphrag/experimental/pipeline/pipeline.py +++ b/src/neo4j_graphrag/experimental/pipeline/pipeline.py @@ -44,9 +44,9 @@ ) from neo4j_graphrag.experimental.pipeline.stores import InMemoryStore, ResultStore from neo4j_graphrag.experimental.pipeline.types import ( - ComponentConfig, - ConnectionConfig, - PipelineConfig, + ComponentDefinition, + ConnectionDefinition, + PipelineDefinition, ) logger = logging.getLogger(__name__) @@ -349,16 +349,34 @@ def __init__(self, store: Optional[ResultStore] = None) -> None: @classmethod def from_template( - cls, pipeline_template: PipelineConfig, store: Optional[ResultStore] = None + cls, pipeline_template: PipelineDefinition, store: Optional[ResultStore] = None ) -> Pipeline: - """Create a Pipeline from a pydantic model defining the components and their connections""" + warnings.warn( + "from_template is deprecated, use from_definition instead", + DeprecationWarning, + stacklevel=2, + ) + return cls.from_definition(pipeline_template, store) + + @classmethod + def from_definition( + cls, + pipeline_definition: PipelineDefinition, + store: Optional[ResultStore] = None, + ) -> Pipeline: + """Create a Pipeline from a pydantic model defining the components and their connections + + Args: + pipeline_definition (PipelineDefinition): An object defining components and how they are connected to each other. + store (Optional[ResultStore]): Where the results are stored. By default, uses the InMemoryStore. + """ pipeline = Pipeline(store=store) - for component in pipeline_template.components: + for component in pipeline_definition.components: pipeline.add_component( component.component, component.name, ) - for edge in pipeline_template.connections: + for edge in pipeline_definition.connections: pipeline_edge = PipelineEdge( edge.start, edge.end, data={"input_config": edge.input_config} ) @@ -369,18 +387,18 @@ def show_as_dict(self) -> dict[str, Any]: component_config = [] for name, task in self._nodes.items(): component_config.append( - ComponentConfig(name=name, component=task.component) + ComponentDefinition(name=name, component=task.component) ) connection_config = [] for edge in self._edges: connection_config.append( - ConnectionConfig( + ConnectionDefinition( start=edge.start, end=edge.end, input_config=edge.data["input_config"] if edge.data else {}, ) ) - pipeline_config = PipelineConfig( + pipeline_config = PipelineDefinition( components=component_config, connections=connection_config ) return pipeline_config.model_dump() diff --git a/src/neo4j_graphrag/experimental/pipeline/types.py b/src/neo4j_graphrag/experimental/pipeline/types.py index ebdf141d..47aafd8b 100644 --- a/src/neo4j_graphrag/experimental/pipeline/types.py +++ b/src/neo4j_graphrag/experimental/pipeline/types.py @@ -14,29 +14,36 @@ # limitations under the License. from __future__ import annotations -from typing import Union +from collections import defaultdict +from typing import Any, Union from pydantic import BaseModel, ConfigDict from neo4j_graphrag.experimental.pipeline.component import Component -class ComponentConfig(BaseModel): +class ComponentDefinition(BaseModel): name: str component: Component + run_params: dict[str, Any] = {} model_config = ConfigDict(arbitrary_types_allowed=True) -class ConnectionConfig(BaseModel): +class ConnectionDefinition(BaseModel): start: str end: str input_config: dict[str, str] -class PipelineConfig(BaseModel): - components: list[ComponentConfig] - connections: list[ConnectionConfig] +class PipelineDefinition(BaseModel): + components: list[ComponentDefinition] + connections: list[ConnectionDefinition] + + def get_run_params(self) -> defaultdict[str, dict[str, Any]]: + return defaultdict( + dict, {c.name: c.run_params for c in self.components if c.run_params} + ) EntityInputType = Union[str, dict[str, Union[str, list[dict[str, str]]]]] diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py index 70ca0193..42c21cf8 100644 --- a/tests/e2e/conftest.py +++ b/tests/e2e/conftest.py @@ -14,6 +14,7 @@ # limitations under the License. from __future__ import annotations +import os import random import string import uuid @@ -33,6 +34,8 @@ from ..e2e.utils import EMBEDDING_BIOLOGY +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + @pytest.fixture(scope="module") def driver() -> Generator[Any, Any, Any]: @@ -48,6 +51,12 @@ def llm() -> MagicMock: return MagicMock(spec=LLMInterface) +@pytest.fixture +def embedder() -> Embedder: + embedder = MagicMock(spec=Embedder) + return embedder + + class RandomEmbedder(Embedder): def embed_query(self, text: str) -> list[float]: return [random.random() for _ in range(1536)] @@ -75,6 +84,31 @@ def retriever_mock() -> MagicMock: return MagicMock(spec=VectorRetriever) +@pytest.fixture +def harry_potter_text() -> str: + with open(os.path.join(BASE_DIR, "data/documents/harry_potter.txt"), "r") as f: + text = f.read() + return text + + +@pytest.fixture +def harry_potter_text_part1() -> str: + with open( + os.path.join(BASE_DIR, "data/documents/harry_potter_part1.txt"), "r" + ) as f: + text = f.read() + return text + + +@pytest.fixture +def harry_potter_text_part2() -> str: + with open( + os.path.join(BASE_DIR, "data/documents/harry_potter_part2.txt"), "r" + ) as f: + text = f.read() + return text + + @pytest.fixture(scope="module") def setup_neo4j_for_retrieval(driver: Driver) -> None: vector_index_name = "vector-index-name" diff --git a/tests/e2e/data/config_files/pipeline_config.json b/tests/e2e/data/config_files/pipeline_config.json new file mode 100644 index 00000000..fe36624d --- /dev/null +++ b/tests/e2e/data/config_files/pipeline_config.json @@ -0,0 +1,72 @@ +{ + "version_": "1", + "template_": "none", + "name": "", + "neo4j_config": { + "params_": { + "uri": { + "resolver_": "ENV", + "var_": "NEO4J_URI" + }, + "user": { + "resolver_": "ENV", + "var_": "NEO4J_USER" + }, + "password": { + "resolver_": "ENV", + "var_": "NEO4J_PASSWORD" + } + } + }, + "extras": { + "database": "neo4j" + }, + "component_config": { + "splitter": { + "class_": "text_splitters.fixed_size_splitter.FixedSizeSplitter", + "params_": { + "chunk_size": 100, + "chunk_overlap": 10 + } + }, + "builder": { + "class_": "lexical_graph.LexicalGraphBuilder", + "params_": { + "config": { + "chunk_node_label": "TextPart" + } + } + }, + "writer": { + "name_": "writer", + "class_": "kg_writer.Neo4jWriter", + "params_": { + "driver": { + "resolver_": "CONFIG_KEY", + "key_": "neo4j_config.default" + }, + "neo4j_database": { + "resolver_": "CONFIG_KEY", + "key_": "extras.database" + } + } + } + }, + "connection_config": [ + { + "start": "splitter", + "end": "builder", + "input_config": { + "text_chunks": "splitter" + } + }, + { + "start": "builder", + "end": "writer", + "input_config": { + "graph": "builder.graph", + "lexical_graph_config": "builder.config" + } + } + ] +} diff --git a/tests/e2e/data/config_files/pipeline_config.yaml b/tests/e2e/data/config_files/pipeline_config.yaml new file mode 100644 index 00000000..87ac905e --- /dev/null +++ b/tests/e2e/data/config_files/pipeline_config.yaml @@ -0,0 +1,45 @@ +version_: "1" +template_: none +neo4j_config: + params_: + uri: + resolver_: ENV + var_: NEO4J_URI + user: + resolver_: ENV + var_: NEO4J_USER + password: + resolver_: ENV + var_: NEO4J_PASSWORD +extras: + database: neo4j +component_config: + splitter: + class_: text_splitters.fixed_size_splitter.FixedSizeSplitter + params_: + chunk_size: 100 + chunk_overlap: 10 + builder: + class_: lexical_graph.LexicalGraphBuilder + params_: + config: + chunk_node_label: TextPart + writer: + class_: kg_writer.Neo4jWriter + params_: + driver: + resolver_: CONFIG_KEY + key_: neo4j_config.default + neo4j_database: + resolver_: CONFIG_KEY + key_: extras.database +connection_config: + - start: splitter + end: builder + input_config: + text_chunks: splitter + - start: builder + end: writer + input_config: + graph: builder.graph + lexical_graph_config: builder.config diff --git a/tests/e2e/data/config_files/simple_kg_pipeline_config.json b/tests/e2e/data/config_files/simple_kg_pipeline_config.json new file mode 100644 index 00000000..c2d629fb --- /dev/null +++ b/tests/e2e/data/config_files/simple_kg_pipeline_config.json @@ -0,0 +1,64 @@ +{ + "version_": "1", + "template_": "SimpleKGPipeline", + "neo4j_config": { + "params_": { + "uri": { + "resolver_": "ENV", + "var_": "NEO4J_URI" + }, + "user": { + "resolver_": "ENV", + "var_": "NEO4J_USER" + }, + "password": { + "resolver_": "ENV", + "var_": "NEO4J_PASSWORD" + } + } + }, + "llm_config": { + "class_": "OpenAILLM", + "params_": { + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY" + }, + "model_name": "gpt-4o", + "model_params": { + "temperature": 0, + "max_tokens": 2000, + "response_format": {"type": "json_object"} + } + } + }, + "embedder_config": { + "class_": "OpenAIEmbeddings", + "params_": { + "api_key": { + "resolver_": "ENV", + "var_": "OPENAI_API_KEY" + } + } + }, + "from_pdf": true, + "entities": [ + "Person", + "Organization", + "Horcrux", + "Location" + ], + "relations": [ + "SITUATED_AT", + "INTERACTS", + "OWNS", + "LED_BY" + ], + "potential_schema": [ + ["Person", "SITUATED_AT", "Location"], + ["Person", "INTERACTS", "Person"], + ["Person", "OWNS", "Horcrux"], + ["Organization", "LED_BY", "Person"] + ], + "perform_entity_resolution": true +} diff --git a/tests/e2e/data/config_files/simple_kg_pipeline_config.yaml b/tests/e2e/data/config_files/simple_kg_pipeline_config.yaml new file mode 100644 index 00000000..abcf9632 --- /dev/null +++ b/tests/e2e/data/config_files/simple_kg_pipeline_config.yaml @@ -0,0 +1,50 @@ +version_: "1" +template_: SimpleKGPipeline +neo4j_config: + params_: + uri: + resolver_: ENV + var_: NEO4J_URI + user: + resolver_: ENV + var_: NEO4J_USER + password: + resolver_: ENV + var_: NEO4J_PASSWORD +llm_config: + class_: OpenAILLM + params_: + api_key: + resolver_: ENV + var_: OPENAI_API_KEY + model_name: gpt-4o + model_params: + temperature: 0 + max_tokens: 2000 + response_format: + type: json_object +embedder_config: + class_: OpenAIEmbeddings + params_: + api_key: + resolver_: ENV + var_: OPENAI_API_KEY +from_pdf: true +entities: + - Person + - Organization + - Location + - Horcrux +relations: + - SITUATED_AT + - INTERACTS + - OWNS + - LED_BY +potential_schema: + - ["Person", "SITUATED_AT", "Location"] + - ["Person", "INTERACTS", "Person"] + - ["Person", "OWNS", "Horcrux"] + - ["Organization", "LED_BY", "Person"] +text_splitter: + class_: text_splitters.fixed_size_splitter.FixedSizeSplitter +perform_entity_resolution: true diff --git a/tests/e2e/data/documents/harry_potter.pdf b/tests/e2e/data/documents/harry_potter.pdf new file mode 100644 index 0000000000000000000000000000000000000000..49f0f6bdfea2aea288155867945c0ee6e73db225 GIT binary patch literal 26810 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

eOL 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 Any: + driver.execute_query("MATCH (n) DETACH DELETE n") + yield + + +@pytest.mark.asyncio +async def test_pipeline_from_json_config(harry_potter_text: str, driver: Mock) -> None: + os.environ["NEO4J_URI"] = "neo4j://localhost:7687" + os.environ["NEO4J_USER"] = "neo4j" + os.environ["NEO4J_PASSWORD"] = "password" + + runner = PipelineRunner.from_config_file( + "tests/e2e/data/config_files/pipeline_config.json" + ) + res = await runner.run({"splitter": {"text": harry_potter_text}}) + assert isinstance(res, PipelineResult) + assert res.result["writer"]["metadata"] == { + "node_count": 11, + "relationship_count": 10, + } + nodes = driver.execute_query("MATCH (n) RETURN n") + assert len(nodes.records) == 11 + + +@pytest.mark.asyncio +async def test_pipeline_from_yaml_config(harry_potter_text: str, driver: Mock) -> None: + os.environ["NEO4J_URI"] = "neo4j://localhost:7687" + os.environ["NEO4J_USER"] = "neo4j" + os.environ["NEO4J_PASSWORD"] = "password" + + runner = PipelineRunner.from_config_file( + "tests/e2e/data/config_files/pipeline_config.yaml" + ) + res = await runner.run({"splitter": {"text": harry_potter_text}}) + assert isinstance(res, PipelineResult) + assert res.result["writer"]["metadata"] == { + "node_count": 11, + "relationship_count": 10, + } + + nodes = driver.execute_query("MATCH (n) RETURN n") + assert len(nodes.records) == 11 + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.runner.SimpleKGPipelineConfig.get_default_embedder" +) +@patch( + "neo4j_graphrag.experimental.pipeline.config.runner.SimpleKGPipelineConfig.get_default_llm" +) +@pytest.mark.asyncio +async def test_simple_kg_pipeline_from_json_config( + mock_llm: Mock, mock_embedder: Mock, harry_potter_text: str, driver: Mock +) -> None: + mock_llm.return_value.ainvoke = AsyncMock( + side_effect=[ + LLMResponse( + content="""{ + "nodes": [ + { + "id": "0", + "label": "Person", + "properties": { + "name": "Harry Potter" + } + }, + { + "id": "1", + "label": "Person", + "properties": { + "name": "Alastor Mad-Eye Moody" + } + }, + { + "id": "2", + "label": "Organization", + "properties": { + "name": "The Order of the Phoenix" + } + } + ], + "relationships": [ + { + "type": "KNOWS", + "start_node_id": "0", + "end_node_id": "1" + }, + { + "type": "LED_BY", + "start_node_id": "2", + "end_node_id": "1" + } + ] + }""" + ), + ] + ) + mock_embedder.return_value.embed_query.side_effect = [ + [1.0, 2.0], + ] + + os.environ["NEO4J_URI"] = "neo4j://localhost:7687" + os.environ["NEO4J_USER"] = "neo4j" + os.environ["NEO4J_PASSWORD"] = "password" + os.environ["OPENAI_API_KEY"] = "sk-my-secret-key" + + runner = PipelineRunner.from_config_file( + "tests/e2e/data/config_files/simple_kg_pipeline_config.json" + ) + res = await runner.run({"file_path": "tests/e2e/data/documents/harry_potter.pdf"}) + assert isinstance(res, PipelineResult) + # print(await runner.pipeline.store.get_result_for_component(res.run_id, "splitter")) + assert res.result["resolver"] == { + "number_of_nodes_to_resolve": 3, + "number_of_created_nodes": 3, + } + nodes = driver.execute_query("MATCH (n) RETURN n") + # 1 chunk + 1 document + 3 nodes + assert len(nodes.records) == 5 + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.runner.SimpleKGPipelineConfig.get_default_embedder" +) +@patch( + "neo4j_graphrag.experimental.pipeline.config.runner.SimpleKGPipelineConfig.get_default_llm" +) +@pytest.mark.asyncio +async def test_simple_kg_pipeline_from_yaml_config( + mock_llm: Mock, mock_embedder: Mock, harry_potter_text: str, driver: Mock +) -> None: + mock_llm.return_value.ainvoke = AsyncMock( + side_effect=[ + LLMResponse( + content="""{ + "nodes": [ + { + "id": "0", + "label": "Person", + "properties": { + "name": "Harry Potter" + } + }, + { + "id": "1", + "label": "Person", + "properties": { + "name": "Alastor Mad-Eye Moody" + } + }, + { + "id": "2", + "label": "Organization", + "properties": { + "name": "The Order of the Phoenix" + } + } + ], + "relationships": [ + { + "type": "KNOWS", + "start_node_id": "0", + "end_node_id": "1" + }, + { + "type": "LED_BY", + "start_node_id": "2", + "end_node_id": "1" + } + ] + }""" + ), + ] + ) + mock_embedder.return_value.embed_query.side_effect = [ + [1.0, 2.0], + ] + + os.environ["NEO4J_URI"] = "neo4j://localhost:7687" + os.environ["NEO4J_USER"] = "neo4j" + os.environ["NEO4J_PASSWORD"] = "password" + os.environ["OPENAI_API_KEY"] = "sk-my-secret-key" + + runner = PipelineRunner.from_config_file( + "tests/e2e/data/config_files/simple_kg_pipeline_config.yaml" + ) + res = await runner.run({"file_path": "tests/e2e/data/documents/harry_potter.pdf"}) + assert isinstance(res, PipelineResult) + # print(await runner.pipeline.store.get_result_for_component(res.run_id, "splitter")) + assert res.result["resolver"] == { + "number_of_nodes_to_resolve": 3, + "number_of_created_nodes": 3, + } + nodes = driver.execute_query("MATCH (n) RETURN n") + # 1 chunk + 1 document + 3 nodes + assert len(nodes.records) == 5 diff --git a/tests/e2e/test_kg_builder_pipeline_e2e.py b/tests/e2e/test_kg_builder_pipeline_e2e.py index 1713098b..bf74470c 100644 --- a/tests/e2e/test_kg_builder_pipeline_e2e.py +++ b/tests/e2e/test_kg_builder_pipeline_e2e.py @@ -124,31 +124,6 @@ def kg_builder_pipeline( return pipe -@pytest.fixture -def harry_potter_text() -> str: - with open(os.path.join(BASE_DIR, "data/harry_potter.txt"), "r") as f: - text = f.read() - return text - - -@pytest.fixture -def harry_potter_text_part1() -> str: - with open( - os.path.join(BASE_DIR, "data/documents/harry_potter_part1.txt"), "r" - ) as f: - text = f.read() - return text - - -@pytest.fixture -def harry_potter_text_part2() -> str: - with open( - os.path.join(BASE_DIR, "data/documents/harry_potter_part2.txt"), "r" - ) as f: - text = f.read() - return text - - @pytest.mark.asyncio @pytest.mark.usefixtures("setup_neo4j_for_kg_construction") async def test_pipeline_builder_happy_path( diff --git a/tests/e2e/test_simplekgpipeline_e2e.py b/tests/e2e/test_simplekgpipeline_e2e.py index def867f5..4d3059c7 100644 --- a/tests/e2e/test_simplekgpipeline_e2e.py +++ b/tests/e2e/test_simplekgpipeline_e2e.py @@ -14,36 +14,13 @@ # limitations under the License. from __future__ import annotations -import os from unittest.mock import MagicMock import neo4j import pytest -from neo4j_graphrag.embeddings.base import Embedder from neo4j_graphrag.experimental.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline -from neo4j_graphrag.llm import LLMInterface, LLMResponse - -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) - - -@pytest.fixture -def llm() -> LLMInterface: - llm = MagicMock(spec=LLMInterface) - return llm - - -@pytest.fixture -def embedder() -> Embedder: - embedder = MagicMock(spec=Embedder) - return embedder - - -@pytest.fixture -def harry_potter_text() -> str: - with open(os.path.join(BASE_DIR, "data/harry_potter.txt"), "r") as f: - text = f.read() - return text +from neo4j_graphrag.llm import LLMResponse @pytest.mark.asyncio diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 829cad23..5069ab6e 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -19,6 +19,7 @@ import neo4j import pytest from neo4j_graphrag.embeddings.base import Embedder +from neo4j_graphrag.experimental.pipeline import Component from neo4j_graphrag.llm import LLMInterface from neo4j_graphrag.retrievers import ( HybridRetriever, @@ -98,3 +99,8 @@ def format_function(record: neo4j.Record) -> RetrieverResultItem: ) return format_function + + +@pytest.fixture(scope="function") +def component() -> MagicMock: + return MagicMock(spec=Component) diff --git a/tests/unit/experimental/pipeline/config/__init__.py b/tests/unit/experimental/pipeline/config/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/experimental/pipeline/config/template_pipeline/__init__.py b/tests/unit/experimental/pipeline/config/template_pipeline/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/experimental/pipeline/config/template_pipeline/test_base.py b/tests/unit/experimental/pipeline/config/template_pipeline/test_base.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py new file mode 100644 index 00000000..e8d12095 --- /dev/null +++ b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py @@ -0,0 +1,301 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import Mock, patch + +import neo4j +import pytest +from neo4j_graphrag.embeddings import Embedder +from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder +from neo4j_graphrag.experimental.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, + OnError, +) +from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter +from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader +from neo4j_graphrag.experimental.components.schema import ( + SchemaBuilder, + SchemaEntity, + SchemaRelation, +) +from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) +from neo4j_graphrag.experimental.pipeline.config.object_config import ComponentConfig +from neo4j_graphrag.experimental.pipeline.config.template_pipeline import ( + SimpleKGPipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError +from neo4j_graphrag.generation.prompts import ERExtractionTemplate +from neo4j_graphrag.llm import LLMInterface + + +def test_simple_kg_pipeline_config_pdf_loader_from_pdf_is_false() -> None: + config = SimpleKGPipelineConfig(from_pdf=False) + assert config._get_pdf_loader() is None + + +def test_simple_kg_pipeline_config_pdf_loader_from_pdf_is_true() -> None: + config = SimpleKGPipelineConfig(from_pdf=True) + assert isinstance(config._get_pdf_loader(), PdfLoader) + + +def test_simple_kg_pipeline_config_pdf_loader_from_pdf_is_true_class_overwrite() -> ( + None +): + my_pdf_loader = PdfLoader() + config = SimpleKGPipelineConfig(from_pdf=True, pdf_loader=my_pdf_loader) # type: ignore + assert config._get_pdf_loader() == my_pdf_loader + + +def test_simple_kg_pipeline_config_pdf_loader_class_overwrite_but_from_pdf_is_false() -> ( + None +): + my_pdf_loader = PdfLoader() + config = SimpleKGPipelineConfig(from_pdf=False, pdf_loader=my_pdf_loader) # type: ignore + assert config._get_pdf_loader() is None + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") +def test_simple_kg_pipeline_config_pdf_loader_from_pdf_is_true_class_overwrite_from_config( + mock_component_parse: Mock, +) -> None: + my_pdf_loader_config = ComponentConfig( + class_="", + ) + my_pdf_loader = PdfLoader() + mock_component_parse.return_value = my_pdf_loader + config = SimpleKGPipelineConfig( + from_pdf=True, + pdf_loader=my_pdf_loader_config, # type: ignore + ) + assert config._get_pdf_loader() == my_pdf_loader + + +def test_simple_kg_pipeline_config_text_splitter() -> None: + config = SimpleKGPipelineConfig() + assert isinstance(config._get_splitter(), FixedSizeSplitter) + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") +def test_simple_kg_pipeline_config_text_splitter_overwrite( + mock_component_parse: Mock, +) -> None: + my_text_splitter_config = ComponentConfig( + class_="", + ) + my_text_splitter = FixedSizeSplitter() + mock_component_parse.return_value = my_text_splitter + config = SimpleKGPipelineConfig( + text_splitter=my_text_splitter_config, # type: ignore + ) + assert config._get_splitter() == my_text_splitter + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.template_pipeline.simple_kg_builder.SimpleKGPipelineConfig.get_default_embedder" +) +def test_simple_kg_pipeline_config_chunk_embedder( + mock_embedder: Mock, embedder: Embedder +) -> None: + mock_embedder.return_value = embedder + config = SimpleKGPipelineConfig() + chunk_embedder = config._get_chunk_embedder() + assert isinstance(chunk_embedder, TextChunkEmbedder) + assert chunk_embedder._embedder == embedder + + +def test_simple_kg_pipeline_config_schema() -> None: + config = SimpleKGPipelineConfig() + assert isinstance(config._get_schema(), SchemaBuilder) + + +def test_simple_kg_pipeline_config_schema_run_params() -> None: + config = SimpleKGPipelineConfig( + entities=["Person"], + relations=["KNOWS"], + potential_schema=[("Person", "KNOWS", "Person")], + ) + assert config._get_run_params_for_schema() == { + "entities": [SchemaEntity(label="Person")], + "relations": [SchemaRelation(label="KNOWS")], + "potential_schema": [ + ("Person", "KNOWS", "Person"), + ], + } + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.template_pipeline.simple_kg_builder.SimpleKGPipelineConfig.get_default_llm" +) +def test_simple_kg_pipeline_config_extractor(mock_llm: Mock, llm: LLMInterface) -> None: + mock_llm.return_value = llm + config = SimpleKGPipelineConfig( + on_error="IGNORE", # type: ignore + prompt_template=ERExtractionTemplate(template="my template {text}"), + ) + extractor = config._get_extractor() + assert isinstance(extractor, LLMEntityRelationExtractor) + assert extractor.llm == llm + assert extractor.on_error == OnError.IGNORE + assert extractor.prompt_template.template == "my template {text}" + + +@patch( + "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", + return_value=(5, 23, 0), +) +@patch( + "neo4j_graphrag.experimental.pipeline.config.template_pipeline.simple_kg_builder.SimpleKGPipelineConfig.get_default_neo4j_driver" +) +def test_simple_kg_pipeline_config_writer( + mock_driver: Mock, + _: Mock, + driver: neo4j.Driver, +) -> None: + mock_driver.return_value = driver + config = SimpleKGPipelineConfig( + neo4j_database="my_db", + ) + writer = config._get_writer() + assert isinstance(writer, Neo4jWriter) + assert writer.driver == driver + assert writer.neo4j_database == "my_db" + + +@patch( + "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", + return_value=(5, 23, 0), +) +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") +def test_simple_kg_pipeline_config_writer_overwrite( + mock_component_parse: Mock, + _: Mock, + driver: neo4j.Driver, +) -> None: + my_writer_config = ComponentConfig( + class_="", + ) + my_writer = Neo4jWriter(driver, neo4j_database="my_db") + mock_component_parse.return_value = my_writer + config = SimpleKGPipelineConfig( + kg_writer=my_writer_config, # type: ignore + neo4j_database="my_other_db", + ) + writer: Neo4jWriter = config._get_writer() # type: ignore + assert writer == my_writer + # database not changed: + assert writer.neo4j_database == "my_db" + + +def test_simple_kg_pipeline_config_connections_from_pdf() -> None: + config = SimpleKGPipelineConfig( + from_pdf=True, + perform_entity_resolution=False, + ) + connections = config._get_connections() + assert len(connections) == 5 + expected_connections = [ + ("pdf_loader", "splitter"), + ("schema", "extractor"), + ("splitter", "chunk_embedder"), + ("chunk_embedder", "extractor"), + ("extractor", "writer"), + ] + for actual, expected in zip(connections, expected_connections): + assert (actual.start, actual.end) == expected + + +def test_simple_kg_pipeline_config_connections_from_text() -> None: + config = SimpleKGPipelineConfig( + from_pdf=False, + perform_entity_resolution=False, + ) + connections = config._get_connections() + assert len(connections) == 4 + expected_connections = [ + ("schema", "extractor"), + ("splitter", "chunk_embedder"), + ("chunk_embedder", "extractor"), + ("extractor", "writer"), + ] + for actual, expected in zip(connections, expected_connections): + assert (actual.start, actual.end) == expected + + +def test_simple_kg_pipeline_config_connections_with_er() -> None: + config = SimpleKGPipelineConfig( + from_pdf=True, + perform_entity_resolution=True, + ) + connections = config._get_connections() + assert len(connections) == 6 + expected_connections = [ + ("pdf_loader", "splitter"), + ("schema", "extractor"), + ("splitter", "chunk_embedder"), + ("chunk_embedder", "extractor"), + ("extractor", "writer"), + ("writer", "resolver"), + ] + for actual, expected in zip(connections, expected_connections): + assert (actual.start, actual.end) == expected + + +def test_simple_kg_pipeline_config_run_params_from_pdf_file_path() -> None: + config = SimpleKGPipelineConfig(from_pdf=True) + assert config.get_run_params({"file_path": "my_file"}) == { + "pdf_loader": {"filepath": "my_file"} + } + + +def test_simple_kg_pipeline_config_run_params_from_text_text() -> None: + config = SimpleKGPipelineConfig(from_pdf=False) + assert config.get_run_params({"text": "my text"}) == { + "splitter": {"text": "my text"} + } + + +def test_simple_kg_pipeline_config_run_params_from_pdf_text() -> None: + config = SimpleKGPipelineConfig(from_pdf=True) + with pytest.raises(PipelineDefinitionError) as excinfo: + config.get_run_params({"text": "my text"}) + assert "Expected 'file_path' argument when 'from_pdf' is True" in str(excinfo) + + +def test_simple_kg_pipeline_config_run_params_from_text_file_path() -> None: + config = SimpleKGPipelineConfig(from_pdf=False) + with pytest.raises(PipelineDefinitionError) as excinfo: + config.get_run_params({"file_path": "my file"}) + assert "Expected 'text' argument when 'from_pdf' is False" in str(excinfo) + + +def test_simple_kg_pipeline_config_run_params_no_file_no_text() -> None: + config = SimpleKGPipelineConfig(from_pdf=False) + with pytest.raises(PipelineDefinitionError) as excinfo: + config.get_run_params({}) + assert ( + "Use either 'text' (when from_pdf=False) or 'file_path' (when from_pdf=True) argument." + in str(excinfo) + ) + + +def test_simple_kg_pipeline_config_run_params_both_file_and_text() -> None: + config = SimpleKGPipelineConfig(from_pdf=False) + with pytest.raises(PipelineDefinitionError) as excinfo: + config.get_run_params({"text": "my text", "file_path": "my file"}) + assert ( + "Use either 'text' (when from_pdf=False) or 'file_path' (when from_pdf=True) argument." + in str(excinfo) + ) diff --git a/tests/unit/experimental/pipeline/config/test_base.py b/tests/unit/experimental/pipeline/config/test_base.py new file mode 100644 index 00000000..20332a79 --- /dev/null +++ b/tests/unit/experimental/pipeline/config/test_base.py @@ -0,0 +1,37 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import patch + +from neo4j_graphrag.experimental.pipeline.config.base import AbstractConfig +from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( + ParamToResolveConfig, +) + + +def test_resolve_param_with_param_to_resolve_object() -> None: + c = AbstractConfig() + with patch( + "neo4j_graphrag.experimental.pipeline.config.param_resolver.ParamToResolveConfig", + spec=ParamToResolveConfig, + ) as mock_param_class: + mock_param = mock_param_class.return_value + mock_param.resolve.return_value = 1 + assert c.resolve_param(mock_param) == 1 + mock_param.resolve.assert_called_once_with({}) + + +def test_resolve_param_with_other_object() -> None: + c = AbstractConfig() + assert c.resolve_param("value") == "value" diff --git a/tests/unit/experimental/pipeline/config/test_object_config.py b/tests/unit/experimental/pipeline/config/test_object_config.py new file mode 100644 index 00000000..baa3c767 --- /dev/null +++ b/tests/unit/experimental/pipeline/config/test_object_config.py @@ -0,0 +1,164 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import patch + +import neo4j +import pytest +from neo4j_graphrag.embeddings import Embedder, OpenAIEmbeddings +from neo4j_graphrag.experimental.pipeline import Pipeline +from neo4j_graphrag.experimental.pipeline.config.object_config import ( + EmbedderConfig, + EmbedderType, + LLMConfig, + LLMType, + Neo4jDriverConfig, + Neo4jDriverType, + ObjectConfig, +) +from neo4j_graphrag.llm import LLMInterface, OpenAILLM + + +def test_get_class_no_optional_module() -> None: + c: ObjectConfig[object] = ObjectConfig() + klass = c._get_class("neo4j_graphrag.experimental.pipeline.Pipeline") + assert klass == Pipeline + + +def test_get_class_optional_module() -> None: + c: ObjectConfig[object] = ObjectConfig() + klass = c._get_class( + "Pipeline", optional_module="neo4j_graphrag.experimental.pipeline" + ) + assert klass == Pipeline + + +def test_get_class_path_and_optional_module() -> None: + c: ObjectConfig[object] = ObjectConfig() + klass = c._get_class( + "pipeline.Pipeline", optional_module="neo4j_graphrag.experimental" + ) + assert klass == Pipeline + + +def test_get_class_wrong_path() -> None: + c: ObjectConfig[object] = ObjectConfig() + with pytest.raises(ValueError): + c._get_class("MyClass") + + +def test_neo4j_driver_config() -> None: + config = Neo4jDriverConfig.model_validate( + { + "params_": { + "uri": "bolt://", + "user": "a user", + "password": "a password", + } + } + ) + assert config.class_ == "not used" + assert config.params_ == { + "uri": "bolt://", + "user": "a user", + "password": "a password", + } + with patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.neo4j.GraphDatabase.driver" + ) as driver_mock: + driver_mock.return_value = "a driver" + d = config.parse() + driver_mock.assert_called_once_with("bolt://", auth=("a user", "a password")) + assert d == "a driver" # type: ignore + + +def test_neo4j_driver_type_with_driver(driver: neo4j.Driver) -> None: + driver_type = Neo4jDriverType(driver) + assert driver_type.parse() == driver + + +def test_neo4j_driver_type_with_config() -> None: + driver_type = Neo4jDriverType( + Neo4jDriverConfig( + params_={ + "uri": "bolt://", + "user": "", + "password": "", + } + ) + ) + driver = driver_type.parse() + assert isinstance(driver, neo4j.Driver) + + +def test_llm_config() -> None: + config = LLMConfig.model_validate( + { + "class_": "OpenAILLM", + "params_": {"model_name": "gpt-4o", "api_key": "my-api-key"}, + } + ) + assert config.class_ == "OpenAILLM" + assert config.get_module() == "neo4j_graphrag.llm" + assert config.get_interface() == LLMInterface + assert config.params_ == {"model_name": "gpt-4o", "api_key": "my-api-key"} + d = config.parse() + assert isinstance(d, OpenAILLM) + + +def test_llm_type_with_driver(llm: LLMInterface) -> None: + llm_type = LLMType(llm) + assert llm_type.parse() == llm + + +def test_llm_type_with_config() -> None: + llm_type = LLMType( + LLMConfig( + class_="OpenAILLM", + params_={"model_name": "gpt-4o", "api_key": "my-api-key"}, + ) + ) + llm = llm_type.parse() + assert isinstance(llm, OpenAILLM) + + +def test_embedder_config() -> None: + config = EmbedderConfig.model_validate( + { + "class_": "OpenAIEmbeddings", + "params_": {"api_key": "my-api-key"}, + } + ) + assert config.class_ == "OpenAIEmbeddings" + assert config.get_module() == "neo4j_graphrag.embeddings" + assert config.get_interface() == Embedder + assert config.params_ == {"api_key": "my-api-key"} + d = config.parse() + assert isinstance(d, OpenAIEmbeddings) + + +def test_embedder_type_with_embedder(embedder: Embedder) -> None: + embedder_type = EmbedderType(embedder) + assert embedder_type.parse() == embedder + + +def test_embedder_type_with_config() -> None: + embedder_type = EmbedderType( + EmbedderConfig( + class_="OpenAIEmbeddings", + params_={"api_key": "my-api-key"}, + ) + ) + embedder = embedder_type.parse() + assert isinstance(embedder, OpenAIEmbeddings) diff --git a/tests/unit/experimental/pipeline/config/test_param_resolver.py b/tests/unit/experimental/pipeline/config/test_param_resolver.py new file mode 100644 index 00000000..efd4d7e9 --- /dev/null +++ b/tests/unit/experimental/pipeline/config/test_param_resolver.py @@ -0,0 +1,56 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from unittest.mock import patch + +import pytest +from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( + ParamFromEnvConfig, + ParamFromKeyConfig, +) + + +@patch.dict(os.environ, {"MY_KEY": "my_value"}, clear=True) +def test_env_param_config_happy_path() -> None: + resolver = ParamFromEnvConfig(var_="MY_KEY") + assert resolver.resolve({}) == "my_value" + + +@patch.dict(os.environ, {}, clear=True) +def test_env_param_config_missing_env_var() -> None: + resolver = ParamFromEnvConfig(var_="MY_KEY") + assert resolver.resolve({}) is None + + +def test_config_key_param_simple_key() -> None: + resolver = ParamFromKeyConfig(key_="my_key") + assert resolver.resolve({"my_key": "my_value"}) == "my_value" + + +def test_config_key_param_missing_key() -> None: + resolver = ParamFromKeyConfig(key_="my_key") + with pytest.raises(KeyError): + resolver.resolve({}) + + +def test_config_complex_key_param() -> None: + resolver = ParamFromKeyConfig(key_="my_key.my_sub_key") + assert resolver.resolve({"my_key": {"my_sub_key": "value"}}) == "value" + + +def test_config_complex_key_param_missing_subkey() -> None: + resolver = ParamFromKeyConfig(key_="my_key.my_sub_key") + with pytest.raises(KeyError): + resolver.resolve({"my_key": {}}) diff --git a/tests/unit/experimental/pipeline/config/test_pipeline_config.py b/tests/unit/experimental/pipeline/config/test_pipeline_config.py new file mode 100644 index 00000000..4de5874b --- /dev/null +++ b/tests/unit/experimental/pipeline/config/test_pipeline_config.py @@ -0,0 +1,378 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import Mock, patch + +import neo4j +from neo4j_graphrag.embeddings import Embedder +from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.experimental.pipeline.config.object_config import ( + ComponentConfig, + ComponentType, + Neo4jDriverConfig, + Neo4jDriverType, +) +from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( + ParamFromEnvConfig, + ParamFromKeyConfig, +) +from neo4j_graphrag.experimental.pipeline.config.pipeline_config import ( + AbstractPipelineConfig, +) +from neo4j_graphrag.experimental.pipeline.types import ComponentDefinition +from neo4j_graphrag.llm import LLMInterface + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverConfig.parse" +) +def test_abstract_pipeline_config_neo4j_config_is_a_dict_with_params_( + mock_neo4j_config: Mock, +) -> None: + mock_neo4j_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + { + "neo4j_config": { + "params_": { + "uri": "bolt://", + "user": "", + "password": "", + } + } + } + ) + assert isinstance(config.neo4j_config, dict) + assert "default" in config.neo4j_config + config.parse() + mock_neo4j_config.assert_called_once() + assert config._global_data["neo4j_config"]["default"] == "text" + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverConfig.parse" +) +def test_abstract_pipeline_config_neo4j_config_is_a_dict_with_names( + mock_neo4j_config: Mock, +) -> None: + mock_neo4j_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + { + "neo4j_config": { + "my_driver": { + "params_": { + "uri": "bolt://", + "user": "", + "password": "", + } + } + } + } + ) + assert isinstance(config.neo4j_config, dict) + assert "my_driver" in config.neo4j_config + config.parse() + mock_neo4j_config.assert_called_once() + assert config._global_data["neo4j_config"]["my_driver"] == "text" + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverConfig.parse" +) +def test_abstract_pipeline_config_neo4j_config_is_a_dict_with_driver( + mock_neo4j_config: Mock, driver: neo4j.Driver +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "neo4j_config": { + "my_driver": driver, + } + } + ) + assert isinstance(config.neo4j_config, dict) + assert "my_driver" in config.neo4j_config + config.parse() + assert not mock_neo4j_config.called + assert config._global_data["neo4j_config"]["my_driver"] == driver + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverConfig.parse" +) +def test_abstract_pipeline_config_neo4j_config_is_a_driver( + mock_neo4j_config: Mock, driver: neo4j.Driver +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "neo4j_config": driver, + } + ) + assert isinstance(config.neo4j_config, dict) + assert "default" in config.neo4j_config + config.parse() + assert not mock_neo4j_config.called + assert config._global_data["neo4j_config"]["default"] == driver + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.LLMConfig.parse") +def test_abstract_pipeline_config_llm_config_is_a_dict_with_params_( + mock_llm_config: Mock, +) -> None: + mock_llm_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + {"llm_config": {"class_": "OpenAILLM", "params_": {"model_name": "gpt-4o"}}} + ) + assert isinstance(config.llm_config, dict) + assert "default" in config.llm_config + config.parse() + mock_llm_config.assert_called_once() + assert config._global_data["llm_config"]["default"] == "text" + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.LLMConfig.parse") +def test_abstract_pipeline_config_llm_config_is_a_dict_with_names( + mock_llm_config: Mock, +) -> None: + mock_llm_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + { + "llm_config": { + "my_llm": {"class_": "OpenAILLM", "params_": {"model_name": "gpt-4o"}} + } + } + ) + assert isinstance(config.llm_config, dict) + assert "my_llm" in config.llm_config + config.parse() + mock_llm_config.assert_called_once() + assert config._global_data["llm_config"]["my_llm"] == "text" + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.LLMConfig.parse") +def test_abstract_pipeline_config_llm_config_is_a_dict_with_llm( + mock_llm_config: Mock, llm: LLMInterface +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "llm_config": { + "my_llm": llm, + } + } + ) + assert isinstance(config.llm_config, dict) + assert "my_llm" in config.llm_config + config.parse() + assert not mock_llm_config.called + assert config._global_data["llm_config"]["my_llm"] == llm + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.LLMConfig.parse") +def test_abstract_pipeline_config_llm_config_is_a_llm( + mock_llm_config: Mock, llm: LLMInterface +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "llm_config": llm, + } + ) + assert isinstance(config.llm_config, dict) + assert "default" in config.llm_config + config.parse() + assert not mock_llm_config.called + assert config._global_data["llm_config"]["default"] == llm + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderConfig.parse") +def test_abstract_pipeline_config_embedder_config_is_a_dict_with_params_( + mock_embedder_config: Mock, +) -> None: + mock_embedder_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + {"embedder_config": {"class_": "OpenAIEmbeddings", "params_": {}}} + ) + assert isinstance(config.embedder_config, dict) + assert "default" in config.embedder_config + config.parse() + mock_embedder_config.assert_called_once() + assert config._global_data["embedder_config"]["default"] == "text" + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderConfig.parse") +def test_abstract_pipeline_config_embedder_config_is_a_dict_with_names( + mock_embedder_config: Mock, +) -> None: + mock_embedder_config.return_value = "text" + config = AbstractPipelineConfig.model_validate( + { + "embedder_config": { + "my_embedder": {"class_": "OpenAIEmbeddings", "params_": {}} + } + } + ) + assert isinstance(config.embedder_config, dict) + assert "my_embedder" in config.embedder_config + config.parse() + mock_embedder_config.assert_called_once() + assert config._global_data["embedder_config"]["my_embedder"] == "text" + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderConfig.parse") +def test_abstract_pipeline_config_embedder_config_is_a_dict_with_llm( + mock_embedder_config: Mock, embedder: Embedder +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "embedder_config": { + "my_embedder": embedder, + } + } + ) + assert isinstance(config.embedder_config, dict) + assert "my_embedder" in config.embedder_config + config.parse() + assert not mock_embedder_config.called + assert config._global_data["embedder_config"]["my_embedder"] == embedder + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.EmbedderConfig.parse") +def test_abstract_pipeline_config_embedder_config_is_an_embedder( + mock_embedder_config: Mock, embedder: Embedder +) -> None: + config = AbstractPipelineConfig.model_validate( + { + "embedder_config": embedder, + } + ) + assert isinstance(config.embedder_config, dict) + assert "default" in config.embedder_config + config.parse() + assert not mock_embedder_config.called + assert config._global_data["embedder_config"]["default"] == embedder + + +def test_abstract_pipeline_config_parse_global_data_no_extras(driver: Mock) -> None: + config = AbstractPipelineConfig( + neo4j_config={"my_driver": Neo4jDriverType(driver)}, + ) + gd = config._parse_global_data() + assert gd == { + "extras": {}, + "neo4j_config": { + "my_driver": driver, + }, + "llm_config": {}, + "embedder_config": {}, + } + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.param_resolver.ParamFromEnvConfig.resolve" +) +def test_abstract_pipeline_config_parse_global_data_extras( + mock_param_resolver: Mock, +) -> None: + mock_param_resolver.return_value = "my value" + config = AbstractPipelineConfig( + extras={"my_extra_var": ParamFromEnvConfig(var_="some key")}, + ) + gd = config._parse_global_data() + assert gd == { + "extras": {"my_extra_var": "my value"}, + "neo4j_config": {}, + "llm_config": {}, + "embedder_config": {}, + } + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.param_resolver.ParamFromEnvConfig.resolve" +) +@patch( + "neo4j_graphrag.experimental.pipeline.config.object_config.Neo4jDriverType.parse" +) +def test_abstract_pipeline_config_parse_global_data_use_extras_in_other_config( + mock_neo4j_parser: Mock, + mock_param_resolver: Mock, +) -> None: + """Parser is able to read variables in the 'extras' section of config + to instantiate another object (neo4j.Driver in this test case) + """ + mock_param_resolver.side_effect = ["bolt://myhost", "myuser", "mypwd"] + mock_neo4j_parser.return_value = "my driver" + config = AbstractPipelineConfig( + extras={ + "my_extra_uri": ParamFromEnvConfig(var_="some key"), + "my_extra_user": ParamFromEnvConfig(var_="some key"), + "my_extra_pwd": ParamFromEnvConfig(var_="some key"), + }, + neo4j_config={ + "my_driver": Neo4jDriverType( + Neo4jDriverConfig( + params_=dict( + uri=ParamFromKeyConfig(key_="extras.my_extra_uri"), + user=ParamFromKeyConfig(key_="extras.my_extra_user"), + password=ParamFromKeyConfig(key_="extras.my_extra_pwd"), + ) + ) + ) + }, + ) + gd = config._parse_global_data() + expected_extras = { + "my_extra_uri": "bolt://myhost", + "my_extra_user": "myuser", + "my_extra_pwd": "mypwd", + } + assert gd["extras"] == expected_extras + assert gd["neo4j_config"] == {"my_driver": "my driver"} + mock_neo4j_parser.assert_called_once_with({"extras": expected_extras}) + + +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") +def test_abstract_pipeline_config_resolve_component_definition_no_run_params( + mock_component_parse: Mock, + component: Component, +) -> None: + mock_component_parse.return_value = component + config = AbstractPipelineConfig() + component_type = ComponentType(component) + component_definition = config._resolve_component_definition("name", component_type) + assert isinstance(component_definition, ComponentDefinition) + mock_component_parse.assert_called_once_with({}) + assert component_definition.name == "name" + assert component_definition.component == component + assert component_definition.run_params == {} + + +@patch( + "neo4j_graphrag.experimental.pipeline.config.pipeline_config.AbstractPipelineConfig.resolve_params" +) +@patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") +def test_abstract_pipeline_config_resolve_component_definition_with_run_params( + mock_component_parse: Mock, + mock_resolve_params: Mock, + component: Component, +) -> None: + mock_component_parse.return_value = component + mock_resolve_params.return_value = {"param": "resolver param result"} + config = AbstractPipelineConfig() + component_type = ComponentType( + ComponentConfig(class_="", params_={}, run_params_={"param1": "value1"}) + ) + component_definition = config._resolve_component_definition("name", component_type) + assert isinstance(component_definition, ComponentDefinition) + mock_component_parse.assert_called_once_with({}) + assert component_definition.name == "name" + assert component_definition.component == component + assert component_definition.run_params == {"param": "resolver param result"} + mock_resolve_params.assert_called_once_with({"param1": "value1"}) diff --git a/tests/unit/experimental/pipeline/config/test_runner.py b/tests/unit/experimental/pipeline/config/test_runner.py new file mode 100644 index 00000000..327b5221 --- /dev/null +++ b/tests/unit/experimental/pipeline/config/test_runner.py @@ -0,0 +1,56 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import Mock, patch + +from neo4j_graphrag.experimental.pipeline import Pipeline +from neo4j_graphrag.experimental.pipeline.config.pipeline_config import PipelineConfig +from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner +from neo4j_graphrag.experimental.pipeline.types import PipelineDefinition + + +@patch("neo4j_graphrag.experimental.pipeline.pipeline.Pipeline.from_definition") +def test_pipeline_runner_from_def_empty(mock_from_definition: Mock) -> None: + mock_from_definition.return_value = Pipeline() + runner = PipelineRunner( + pipeline_definition=PipelineDefinition(components=[], connections=[]) + ) + assert runner.config is None + assert runner.pipeline is not None + assert runner.pipeline._nodes == {} + assert runner.pipeline._edges == [] + assert runner.run_params == {} + mock_from_definition.assert_called_once() + + +def test_pipeline_runner_from_config() -> None: + config = PipelineConfig(component_config={}, connection_config=[]) + runner = PipelineRunner.from_config(config) + assert runner.config is not None + assert runner.pipeline is not None + assert runner.pipeline._nodes == {} + assert runner.pipeline._edges == [] + assert runner.run_params == {} + + +@patch("neo4j_graphrag.experimental.pipeline.config.runner.PipelineRunner.from_config") +@patch("neo4j_graphrag.experimental.pipeline.config.config_reader.ConfigReader.read") +def test_pipeline_runner_from_config_file( + mock_read: Mock, mock_from_config: Mock +) -> None: + mock_read.return_value = {"dict": "with data"} + PipelineRunner.from_config_file("file.yaml") + + mock_read.assert_called_once_with("file.yaml") + mock_from_config.assert_called_once_with({"dict": "with data"}, do_cleaning=True) diff --git a/tests/unit/experimental/pipeline/test_kg_builder.py b/tests/unit/experimental/pipeline/test_kg_builder.py index b1b29151..bddbac50 100644 --- a/tests/unit/experimental/pipeline/test_kg_builder.py +++ b/tests/unit/experimental/pipeline/test_kg_builder.py @@ -18,10 +18,8 @@ import neo4j import pytest from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import OnError from neo4j_graphrag.experimental.components.schema import ( SchemaEntity, - SchemaProperty, SchemaRelation, ) from neo4j_graphrag.experimental.components.types import LexicalGraphConfig @@ -31,136 +29,6 @@ from neo4j_graphrag.llm.base import LLMInterface -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -@pytest.mark.asyncio -async def test_knowledge_graph_builder_init_with_text(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - from_pdf=False, - ) - - assert kg_builder.llm == llm - assert kg_builder.driver == driver - assert kg_builder.embedder == embedder - assert kg_builder.from_pdf is False - assert kg_builder.entities == [] - assert kg_builder.relations == [] - assert kg_builder.potential_schema == [] - assert "pdf_loader" not in kg_builder.pipeline - - text_input = "May thy knife chip and shatter." - - with patch.object( - kg_builder.pipeline, - "run", - return_value=PipelineResult(run_id="test_run", result=None), - ) as mock_run: - await kg_builder.run_async(text=text_input) - mock_run.assert_called_once() - pipe_inputs = mock_run.call_args[0][0] - assert pipe_inputs["splitter"]["text"] == text_input - - -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -@pytest.mark.asyncio -async def test_knowledge_graph_builder_init_with_file_path(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - from_pdf=True, - ) - - assert kg_builder.llm == llm - assert kg_builder.driver == driver - assert kg_builder.from_pdf is True - assert kg_builder.entities == [] - assert kg_builder.relations == [] - assert kg_builder.potential_schema == [] - assert "pdf_loader" in kg_builder.pipeline - - file_path = "path/to/test.pdf" - - with patch.object( - kg_builder.pipeline, - "run", - return_value=PipelineResult(run_id="test_run", result=None), - ) as mock_run: - await kg_builder.run_async(file_path=file_path) - mock_run.assert_called_once() - pipe_inputs = mock_run.call_args[0][0] - assert pipe_inputs["pdf_loader"]["filepath"] == file_path - - -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -@pytest.mark.asyncio -async def test_knowledge_graph_builder_run_with_both_inputs(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - from_pdf=True, - ) - - text_input = "May thy knife chip and shatter." - file_path = "path/to/test.pdf" - - with pytest.raises(PipelineDefinitionError) as exc_info: - await kg_builder.run_async(file_path=file_path, text=text_input) - - assert "Expected 'file_path' argument when 'from_pdf' is True." in str( - exc_info.value - ) or "Expected 'text' argument when 'from_pdf' is False." in str(exc_info.value) - - -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -@pytest.mark.asyncio -async def test_knowledge_graph_builder_run_with_no_inputs(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - from_pdf=True, - ) - - with pytest.raises(PipelineDefinitionError) as exc_info: - await kg_builder.run_async() - - assert "Expected 'file_path' argument when 'from_pdf' is True." in str( - exc_info.value - ) or "Expected 'text' argument when 'from_pdf' is False." in str(exc_info.value) - - @mock.patch( "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", return_value=(5, 23, 0), @@ -181,13 +49,13 @@ async def test_knowledge_graph_builder_document_info_with_file(_: Mock) -> None: file_path = "path/to/test.pdf" with patch.object( - kg_builder.pipeline, + kg_builder.runner.pipeline, "run", return_value=PipelineResult(run_id="test_run", result=None), ) as mock_run: await kg_builder.run_async(file_path=file_path) - pipe_inputs = mock_run.call_args[0][0] + pipe_inputs = mock_run.call_args[1]["data"] assert "pdf_loader" in pipe_inputs assert pipe_inputs["pdf_loader"] == {"filepath": file_path} assert "extractor" not in pipe_inputs @@ -213,13 +81,13 @@ async def test_knowledge_graph_builder_document_info_with_text(_: Mock) -> None: text_input = "May thy knife chip and shatter." with patch.object( - kg_builder.pipeline, + kg_builder.runner.pipeline, "run", return_value=PipelineResult(run_id="test_run", result=None), ) as mock_run: await kg_builder.run_async(text=text_input) - pipe_inputs = mock_run.call_args[0][0] + pipe_inputs = mock_run.call_args[1]["data"] assert "splitter" in pipe_inputs assert pipe_inputs["splitter"] == {"text": text_input} @@ -248,51 +116,33 @@ async def test_knowledge_graph_builder_with_entities_and_file(_: Mock) -> None: from_pdf=True, ) - internal_entities = [SchemaEntity(label=label) for label in entities] - internal_relations = [SchemaRelation(label=label) for label in relations] - assert kg_builder.entities == internal_entities - assert kg_builder.relations == internal_relations - assert kg_builder.potential_schema == potential_schema + # assert kg_builder.entities == entities + # assert kg_builder.relations == relations + # assert kg_builder.potential_schema == potential_schema file_path = "path/to/test.pdf" + internal_entities = [SchemaEntity(label=label) for label in entities] + internal_relations = [SchemaRelation(label=label) for label in relations] + with patch.object( - kg_builder.pipeline, + kg_builder.runner.pipeline, "run", return_value=PipelineResult(run_id="test_run", result=None), ) as mock_run: await kg_builder.run_async(file_path=file_path) - pipe_inputs = mock_run.call_args[0][0] + pipe_inputs = mock_run.call_args[1]["data"] assert pipe_inputs["schema"]["entities"] == internal_entities assert pipe_inputs["schema"]["relations"] == internal_relations assert pipe_inputs["schema"]["potential_schema"] == potential_schema -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -def test_simple_kg_pipeline_on_error_conversion(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - on_error="RAISE", - ) - - assert kg_builder.on_error == OnError.RAISE - - def test_simple_kg_pipeline_on_error_invalid_value() -> None: llm = MagicMock(spec=LLMInterface) driver = MagicMock(spec=neo4j.Driver) embedder = MagicMock(spec=Embedder) - with pytest.raises(PipelineDefinitionError) as exc_info: + with pytest.raises(PipelineDefinitionError): SimpleKGPipeline( llm=llm, driver=driver, @@ -300,50 +150,6 @@ def test_simple_kg_pipeline_on_error_invalid_value() -> None: on_error="INVALID_VALUE", ) - assert "Expected one of ['RAISE', 'IGNORE']" in str(exc_info.value) - - -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -def test_simple_kg_pipeline_no_entity_resolution(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - on_error="IGNORE", - perform_entity_resolution=False, - ) - - assert "resolver" not in kg_builder.pipeline - - -@mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", - return_value=(5, 23, 0), -) -@pytest.mark.asyncio -def test_simple_kg_pipeline_lexical_graph_config_attribute(_: Mock) -> None: - llm = MagicMock(spec=LLMInterface) - driver = MagicMock(spec=neo4j.Driver) - embedder = MagicMock(spec=Embedder) - - lexical_graph_config = LexicalGraphConfig() - kg_builder = SimpleKGPipeline( - llm=llm, - driver=driver, - embedder=embedder, - on_error="IGNORE", - lexical_graph_config=lexical_graph_config, - ) - - assert kg_builder.lexical_graph_config == lexical_graph_config - @mock.patch( "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._get_version", @@ -372,58 +178,14 @@ async def test_knowledge_graph_builder_with_lexical_graph_config(_: Mock) -> Non text_input = "May thy knife chip and shatter." with patch.object( - kg_builder.pipeline, + kg_builder.runner.pipeline, "run", return_value=PipelineResult(run_id="test_run", result=None), ) as mock_run: await kg_builder.run_async(text=text_input) - pipe_inputs = mock_run.call_args[0][0] + pipe_inputs = mock_run.call_args[1]["data"] assert "extractor" in pipe_inputs assert pipe_inputs["extractor"] == { "lexical_graph_config": lexical_graph_config } - - -def test_knowledge_graph_builder_to_schema_entity_method() -> None: - assert SimpleKGPipeline.to_schema_entity("EntityType") == SchemaEntity( - label="EntityType" - ) - assert SimpleKGPipeline.to_schema_entity({"label": "EntityType"}) == SchemaEntity( - label="EntityType" - ) - assert SimpleKGPipeline.to_schema_entity( - {"label": "EntityType", "description": "A special entity"} - ) == SchemaEntity(label="EntityType", description="A special entity") - assert SimpleKGPipeline.to_schema_entity( - {"label": "EntityType", "properties": []} - ) == SchemaEntity(label="EntityType") - assert SimpleKGPipeline.to_schema_entity( - { - "label": "EntityType", - "properties": [{"name": "entityProperty", "type": "DATE"}], - } - ) == SchemaEntity( - label="EntityType", - properties=[SchemaProperty(name="entityProperty", type="DATE")], - ) - - -def test_knowledge_graph_builder_to_schema_relation_method() -> None: - assert SimpleKGPipeline.to_schema_relation("REL_TYPE") == SchemaRelation( - label="REL_TYPE" - ) - assert SimpleKGPipeline.to_schema_relation({"label": "REL_TYPE"}) == SchemaRelation( - label="REL_TYPE" - ) - assert SimpleKGPipeline.to_schema_relation( - {"label": "REL_TYPE", "description": "A rel type"} - ) == SchemaRelation(label="REL_TYPE", description="A rel type") - assert SimpleKGPipeline.to_schema_relation( - {"label": "REL_TYPE", "properties": []} - ) == SchemaRelation(label="REL_TYPE") - assert SimpleKGPipeline.to_schema_relation( - {"label": "REL_TYPE", "properties": [{"name": "relProperty", "type": "DATE"}]} - ) == SchemaRelation( - label="REL_TYPE", properties=[SchemaProperty(name="relProperty", type="DATE")] - ) From 140a057a7bb6da533254f47120b014f46204f95d Mon Sep 17 00:00:00 2001 From: Estelle Scifo Date: Thu, 12 Dec 2024 15:25:19 +0100 Subject: [PATCH 4/5] Add OllamaLLM and OllamaEmbeddings classes (#231) * Add OllamaLLM and OllamaEmbeddings classes using the ollama python client * Try removing import * :( * Add tests + reformat import in ollama embeddings for consistency with all other imports * Fix after merge --- CHANGELOG.md | 1 + README.md | 1 + docs/source/api.rst | 12 +++ docs/source/index.rst | 1 + docs/source/user_guide_rag.rst | 34 ++------- .../customize/embeddings/ollama_embeddings.py | 11 +-- examples/customize/llms/ollama_llm.py | 11 ++- poetry.lock | 55 +++++++++----- pyproject.toml | 2 + src/neo4j_graphrag/embeddings/__init__.py | 2 + src/neo4j_graphrag/embeddings/mistral.py | 3 +- src/neo4j_graphrag/embeddings/ollama.py | 65 ++++++++++++++++ src/neo4j_graphrag/llm/__init__.py | 2 + src/neo4j_graphrag/llm/ollama_llm.py | 76 +++++++++++++++++++ tests/unit/embeddings/test_ollama_embedder.py | 35 +++++++++ tests/unit/llm/test_ollama_llm.py | 46 +++++++++++ 16 files changed, 293 insertions(+), 64 deletions(-) create mode 100644 src/neo4j_graphrag/embeddings/ollama.py create mode 100644 src/neo4j_graphrag/llm/ollama_llm.py create mode 100644 tests/unit/embeddings/test_ollama_embedder.py create mode 100644 tests/unit/llm/test_ollama_llm.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac264f0..45ebbeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Integrated json-repair package to handle and repair invalid JSON generated by LLMs. - Introduced InvalidJSONError exception for handling cases where JSON repair fails. - Ability to create a Pipeline or SimpleKGPipeline from a config file. See [the example](examples/build_graph/from_config_files/simple_kg_pipeline_from_config_file.py). +- Added `OllamaLLM` and `OllamaEmbeddings` classes to make Ollama support more explicit. Implementations using the `OpenAILLM` and `OpenAIEmbeddings` classes will still work. ## Changed - Updated LLM prompts to include stricter instructions for generating valid JSON. diff --git a/README.md b/README.md index 9fb37a0e..74a2d6dd 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ This package has some optional features that can be enabled using the extra dependencies described below: - LLM providers (at least one is required for RAG and KG Builder Pipeline): + - **ollama**: LLMs from Ollama - **openai**: LLMs from OpenAI (including AzureOpenAI) - **google**: LLMs from Vertex AI - **cohere**: LLMs from Cohere diff --git a/docs/source/api.rst b/docs/source/api.rst index 7d46b3f0..8e52f9a4 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -239,6 +239,12 @@ AzureOpenAIEmbeddings .. autoclass:: neo4j_graphrag.embeddings.openai.AzureOpenAIEmbeddings :members: +OllamaEmbeddings +================ + +.. autoclass:: neo4j_graphrag.embeddings.ollama.OllamaEmbeddings + :members: + VertexAIEmbeddings ================== @@ -286,6 +292,12 @@ AzureOpenAILLM :members: :undoc-members: get_messages, client_class, async_client_class +OllamaLLM +--------- + +.. autoclass:: neo4j_graphrag.llm.ollama_llm.OllamaLLM + :members: + VertexAILLM ----------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 9d6f9a3d..f48bf281 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -88,6 +88,7 @@ Extra dependencies can be installed with: List of extra dependencies: - LLM providers (at least one is required for RAG and KG Builder Pipeline): + - **ollama**: LLMs from Ollama - **openai**: LLMs from OpenAI (including AzureOpenAI) - **google**: LLMs from Vertex AI - **cohere**: LLMs from Cohere diff --git a/docs/source/user_guide_rag.rst b/docs/source/user_guide_rag.rst index 2b2b528b..8074eef7 100644 --- a/docs/source/user_guide_rag.rst +++ b/docs/source/user_guide_rag.rst @@ -218,14 +218,13 @@ See :ref:`coherellm`. Using a Local Model via Ollama ------------------------------- -Similarly to the official OpenAI Python client, the `OpenAILLM` can be -used with Ollama. Assuming Ollama is running on the default address `127.0.0.1:11434`, +Assuming Ollama is running on the default address `127.0.0.1:11434`, it can be queried using the following: .. code:: python - from neo4j_graphrag.llm import OpenAILLM - llm = OpenAILLM(api_key="ollama", base_url="http://127.0.0.1:11434/v1", model_name="orca-mini") + from neo4j_graphrag.llm import OllamaLLM + llm = OllamaLLM(model_name="orca-mini") llm.invoke("say something") @@ -428,6 +427,7 @@ Currently, this package supports the following embedders: - :ref:`mistralaiembeddings` - :ref:`cohereembeddings` - :ref:`azureopenaiembeddings` +- :ref:`ollamaembeddings` The `OpenAIEmbeddings` was illustrated previously. Here is how to use the `SentenceTransformerEmbeddings`: @@ -438,31 +438,7 @@ The `OpenAIEmbeddings` was illustrated previously. Here is how to use the `Sente embedder = SentenceTransformerEmbeddings(model="all-MiniLM-L6-v2") # Note: this is the default model -If another embedder is desired, a custom embedder can be created. For example, consider -the following implementation of an embedder that wraps the `OllamaEmbedding` model from LlamaIndex: - -.. code:: python - - from llama_index.embeddings.ollama import OllamaEmbedding - from neo4j_graphrag.embeddings.base import Embedder - - class OllamaEmbedder(Embedder): - def __init__(self, ollama_embedding): - self.embedder = ollama_embedding - - def embed_query(self, text: str) -> list[float]: - embedding = self.embedder.get_text_embedding_batch( - [text], show_progress=True - ) - return embedding[0] - - ollama_embedding = OllamaEmbedding( - model_name="llama3", - base_url="http://localhost:11434", - ollama_additional_kwargs={"mirostat": 0}, - ) - embedder = OllamaEmbedder(ollama_embedding) - vector = embedder.embed_query("some text") +If another embedder is desired, a custom embedder can be created, using the `Embedder` interface. Other Vector Retriever Configuration diff --git a/examples/customize/embeddings/ollama_embeddings.py b/examples/customize/embeddings/ollama_embeddings.py index 2a5a0046..243cf4b6 100644 --- a/examples/customize/embeddings/ollama_embeddings.py +++ b/examples/customize/embeddings/ollama_embeddings.py @@ -1,15 +1,10 @@ """This example demonstrate how to embed a text into a vector -using OpenAI models and API. +using a local model served by Ollama. """ -from neo4j_graphrag.embeddings import OpenAIEmbeddings +from neo4j_graphrag.embeddings import OllamaEmbeddings -# not used but needs to be provided -api_key = "ollama" - -embeder = OpenAIEmbeddings( - base_url="http://localhost:11434/v1", - api_key=api_key, +embeder = OllamaEmbeddings( model="", ) res = embeder.embed_query("my question") diff --git a/examples/customize/llms/ollama_llm.py b/examples/customize/llms/ollama_llm.py index 56148042..f815d4db 100644 --- a/examples/customize/llms/ollama_llm.py +++ b/examples/customize/llms/ollama_llm.py @@ -1,12 +1,11 @@ -from neo4j_graphrag.llm import LLMResponse, OpenAILLM +"""This example demonstrate how to invoke an LLM using a local model +served by Ollama. +""" -# not used but needs to be provided -api_key = "ollama" +from neo4j_graphrag.llm import LLMResponse, OllamaLLM -llm = OpenAILLM( - base_url="http://localhost:11434/v1", +llm = OllamaLLM( model_name="", - api_key=api_key, ) res: LLMResponse = llm.invoke("What is the additive color model?") print(res.content) diff --git a/poetry.lock b/poetry.lock index a662e717..21f8bf66 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1026,13 +1026,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.36.0" +version = "2.37.0" description = "Google Authentication Library" optional = true python-versions = ">=3.7" files = [ - {file = "google_auth-2.36.0-py2.py3-none-any.whl", hash = "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb"}, - {file = "google_auth-2.36.0.tar.gz", hash = "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1"}, + {file = "google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0"}, + {file = "google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00"}, ] [package.dependencies] @@ -1043,6 +1043,7 @@ rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] @@ -1591,13 +1592,13 @@ trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" -version = "0.27.0" +version = "0.27.2" description = "The next generation HTTP client." optional = true python-versions = ">=3.8" files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, ] [package.dependencies] @@ -1613,6 +1614,7 @@ brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "httpx-sse" @@ -1976,13 +1978,13 @@ langchain-core = ">=0.3.15,<0.4.0" [[package]] name = "langsmith" -version = "0.2.2" +version = "0.2.3" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langsmith-0.2.2-py3-none-any.whl", hash = "sha256:4786d7dcdbc25e43d4a1bf70bbe12938a9eb2364feec8f6fc4d967162519b367"}, - {file = "langsmith-0.2.2.tar.gz", hash = "sha256:6f515ee41ae80968a7d552be1154414ccde57a0a534c960c8c3cd1835734095f"}, + {file = "langsmith-0.2.3-py3-none-any.whl", hash = "sha256:4958b6e918f57fedba6ddc55b8534d1e06478bb44c779aa73713ce898ca6ae87"}, + {file = "langsmith-0.2.3.tar.gz", hash = "sha256:54c231b07fdeb0f8472925074a0ec0ed2cb654a0437d63c6ccf76a9da635900d"}, ] [package.dependencies] @@ -2864,6 +2866,21 @@ files = [ {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, ] +[[package]] +name = "ollama" +version = "0.4.4" +description = "The official Python client for Ollama." +optional = true +python-versions = "<4.0,>=3.8" +files = [ + {file = "ollama-0.4.4-py3-none-any.whl", hash = "sha256:0f466e845e2205a1cbf5a2fef4640027b90beaa3b06c574426d8b6b17fd6e139"}, + {file = "ollama-0.4.4.tar.gz", hash = "sha256:e1db064273c739babc2dde9ea84029c4a43415354741b6c50939ddd3dd0f7ffb"}, +] + +[package.dependencies] +httpx = ">=0.27.0,<0.28.0" +pydantic = ">=2.9.0,<3.0.0" + [[package]] name = "openai" version = "1.57.2" @@ -5053,23 +5070,22 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "weaviate-client" -version = "4.9.6" +version = "4.10.1" description = "A python native Weaviate client" optional = true python-versions = ">=3.9" files = [ - {file = "weaviate_client-4.9.6-py3-none-any.whl", hash = "sha256:1d3b551939c0f7314f25e417cbcf4cf34e7adf942627993eef36ae6b4a044673"}, - {file = "weaviate_client-4.9.6.tar.gz", hash = "sha256:56d67c40fc94b0d53e81e0aa4477baaebbf3646fbec26551df66e396a72adcb6"}, + {file = "weaviate_client-4.10.1-py3-none-any.whl", hash = "sha256:eedd693b2bbd02279109f9a37d2c33492bb460e480f4c5a4297530d4ad78469e"}, + {file = "weaviate_client-4.10.1.tar.gz", hash = "sha256:7a1513d0ce7d918100d255224da52fcfe3d0834a2d22069853ab95a2a17f102c"}, ] [package.dependencies] authlib = ">=1.2.1,<1.3.2" -grpcio = ">=1.57.0,<2.0.0" -grpcio-health-checking = ">=1.57.0,<2.0.0" -grpcio-tools = ">=1.57.0,<2.0.0" -httpx = ">=0.25.0,<=0.27.0" -pydantic = ">=2.5.0,<3.0.0" -requests = ">=2.30.0,<3.0.0" +grpcio = ">=1.66.2,<2.0.0" +grpcio-health-checking = ">=1.66.2,<2.0.0" +grpcio-tools = ">=1.66.2,<2.0.0" +httpx = ">=0.26.0,<0.29.0" +pydantic = ">=2.8.0,<3.0.0" validators = "0.34.0" [[package]] @@ -5269,6 +5285,7 @@ experimental = ["fsspec", "langchain-text-splitters", "llama-index", "pygraphviz google = ["google-cloud-aiplatform"] kg-creation-tools = ["pygraphviz", "pygraphviz"] mistralai = ["mistralai"] +ollama = ["ollama"] openai = ["openai"] pinecone = ["pinecone-client"] qdrant = ["qdrant-client"] @@ -5278,4 +5295,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = "^3.9.0" -content-hash = "5f729b5f7f31021258d04fcf26e2310f685f1b97113e888ba346df5c7393d4e4" +content-hash = "c2ab4d7e2b6f8dfa668cdab458068d085425115cbb08c201d3eb3be32c47325b" diff --git a/pyproject.toml b/pyproject.toml index 604fde99..0cba753d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ anthropic = { version = "^0.36.0", optional = true} sentence-transformers = {version = "^3.0.0", optional = true } json-repair = "^0.30.2" types-pyyaml = "^6.0.12.20240917" +ollama = {version = "^0.4.4", optional = true} [tool.poetry.group.dev.dependencies] urllib3 = "<2" @@ -69,6 +70,7 @@ pinecone = ["pinecone-client"] google = ["google-cloud-aiplatform"] cohere = ["cohere"] anthropic = ["anthropic"] +ollama = ["ollama"] openai = ["openai"] mistralai = ["mistralai"] qdrant = ["qdrant-client"] diff --git a/src/neo4j_graphrag/embeddings/__init__.py b/src/neo4j_graphrag/embeddings/__init__.py index 6c30951d..9398eefe 100644 --- a/src/neo4j_graphrag/embeddings/__init__.py +++ b/src/neo4j_graphrag/embeddings/__init__.py @@ -15,6 +15,7 @@ from .base import Embedder from .cohere import CohereEmbeddings from .mistral import MistralAIEmbeddings +from .ollama import OllamaEmbeddings from .openai import AzureOpenAIEmbeddings, OpenAIEmbeddings from .sentence_transformers import SentenceTransformerEmbeddings from .vertexai import VertexAIEmbeddings @@ -22,6 +23,7 @@ __all__ = [ "Embedder", "SentenceTransformerEmbeddings", + "OllamaEmbeddings", "OpenAIEmbeddings", "AzureOpenAIEmbeddings", "VertexAIEmbeddings", diff --git a/src/neo4j_graphrag/embeddings/mistral.py b/src/neo4j_graphrag/embeddings/mistral.py index 8c352263..09943019 100644 --- a/src/neo4j_graphrag/embeddings/mistral.py +++ b/src/neo4j_graphrag/embeddings/mistral.py @@ -57,8 +57,7 @@ def embed_query(self, text: str, **kwargs: Any) -> list[float]: **kwargs (Any): Additional keyword arguments to pass to the Mistral AI client. """ embeddings_batch_response = self.mistral_client.embeddings.create( - model=self.model, - inputs=[text], + model=self.model, inputs=[text], **kwargs ) if embeddings_batch_response is None or not embeddings_batch_response.data: raise EmbeddingsGenerationError("Failed to retrieve embeddings.") diff --git a/src/neo4j_graphrag/embeddings/ollama.py b/src/neo4j_graphrag/embeddings/ollama.py new file mode 100644 index 00000000..a3d804a0 --- /dev/null +++ b/src/neo4j_graphrag/embeddings/ollama.py @@ -0,0 +1,65 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import Any + +from neo4j_graphrag.embeddings.base import Embedder +from neo4j_graphrag.exceptions import EmbeddingsGenerationError + + +class OllamaEmbeddings(Embedder): + """ + Ollama embeddings class. + This class uses the ollama Python client to generate vector embeddings for text data. + + Args: + model (str): The name of the Mistral AI text embedding model to use. Defaults to "mistral-embed". + """ + + def __init__(self, model: str, **kwargs: Any) -> None: + try: + import ollama + except ImportError: + raise ImportError( + "Could not import ollama python client. " + "Please install it with `pip install ollama`." + ) + self.model = model + self.client = ollama.Client(**kwargs) + + def embed_query(self, text: str, **kwargs: Any) -> list[float]: + """ + Generate embeddings for a given query using an Ollama text embedding model. + + Args: + text (str): The text to generate an embedding for. + **kwargs (Any): Additional keyword arguments to pass to the Ollama client. + """ + embeddings_response = self.client.embed( + model=self.model, + input=text, + **kwargs, + ) + + if embeddings_response is None or embeddings_response.embeddings is None: + raise EmbeddingsGenerationError("Failed to retrieve embeddings.") + + embedding = embeddings_response.embeddings + if not isinstance(embedding, list): + raise EmbeddingsGenerationError("Embedding is not a list of floats.") + + return embedding diff --git a/src/neo4j_graphrag/llm/__init__.py b/src/neo4j_graphrag/llm/__init__.py index a8fbdd61..a9ece5cc 100644 --- a/src/neo4j_graphrag/llm/__init__.py +++ b/src/neo4j_graphrag/llm/__init__.py @@ -16,6 +16,7 @@ from .base import LLMInterface from .cohere_llm import CohereLLM from .mistralai_llm import MistralAILLM +from .ollama_llm import OllamaLLM from .openai_llm import AzureOpenAILLM, OpenAILLM from .types import LLMResponse from .vertexai_llm import VertexAILLM @@ -25,6 +26,7 @@ "CohereLLM", "LLMResponse", "LLMInterface", + "OllamaLLM", "OpenAILLM", "VertexAILLM", "AzureOpenAILLM", diff --git a/src/neo4j_graphrag/llm/ollama_llm.py b/src/neo4j_graphrag/llm/ollama_llm.py new file mode 100644 index 00000000..d82ccd25 --- /dev/null +++ b/src/neo4j_graphrag/llm/ollama_llm.py @@ -0,0 +1,76 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Any, Optional + +from neo4j_graphrag.exceptions import LLMGenerationError + +from .base import LLMInterface +from .types import LLMResponse + + +class OllamaLLM(LLMInterface): + def __init__( + self, + model_name: str, + model_params: Optional[dict[str, Any]] = None, + **kwargs: Any, + ): + try: + import ollama + except ImportError: + raise ImportError( + "Could not import ollama Python client. " + "Please install it with `pip install ollama`." + ) + super().__init__(model_name, model_params, **kwargs) + self.ollama = ollama + self.client = ollama.Client( + **kwargs, + ) + self.async_client = ollama.AsyncClient( + **kwargs, + ) + + def invoke(self, input: str) -> LLMResponse: + try: + response = self.client.chat( + model=self.model_name, + messages=[ + { + "role": "user", + "content": input, + }, + ], + ) + content = response.message.content or "" + return LLMResponse(content=content) + except self.ollama.ResponseError as e: + raise LLMGenerationError(e) + + async def ainvoke(self, input: str) -> LLMResponse: + try: + response = await self.async_client.chat( + model=self.model_name, + messages=[ + { + "role": "user", + "content": input, + }, + ], + ) + content = response.message.content or "" + return LLMResponse(content=content) + except self.ollama.ResponseError as e: + raise LLMGenerationError(e) diff --git a/tests/unit/embeddings/test_ollama_embedder.py b/tests/unit/embeddings/test_ollama_embedder.py new file mode 100644 index 00000000..dded2b87 --- /dev/null +++ b/tests/unit/embeddings/test_ollama_embedder.py @@ -0,0 +1,35 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import MagicMock, Mock, patch + +import pytest +from neo4j_graphrag.embeddings.ollama import OllamaEmbeddings + + +@patch("builtins.__import__", side_effect=ImportError) +def test_ollama_embedder_missing_dependency(mock_import: Mock) -> None: + with pytest.raises(ImportError): + OllamaEmbeddings(model="test") + + +@patch("builtins.__import__") +def test_ollama_embedder_happy_path(mock_import: Mock) -> None: + mock_import.return_value.Client.return_value.embed.return_value = MagicMock( + embeddings=[1.0, 2.0], + ) + embedder = OllamaEmbeddings(model="test") + res = embedder.embed_query("my text") + assert isinstance(res, list) + assert res == [1.0, 2.0] diff --git a/tests/unit/llm/test_ollama_llm.py b/tests/unit/llm/test_ollama_llm.py new file mode 100644 index 00000000..f7be308b --- /dev/null +++ b/tests/unit/llm/test_ollama_llm.py @@ -0,0 +1,46 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest.mock import MagicMock, Mock, patch + +import ollama +import pytest +from neo4j_graphrag.llm import LLMResponse +from neo4j_graphrag.llm.ollama_llm import OllamaLLM + + +def get_mock_ollama() -> MagicMock: + mock = MagicMock() + mock.ResponseError = ollama.ResponseError + return mock + + +@patch("builtins.__import__", side_effect=ImportError) +def test_ollama_llm_missing_dependency(mock_import: Mock) -> None: + with pytest.raises(ImportError): + OllamaLLM(model_name="gpt-4o") + + +@patch("builtins.__import__") +def test_ollama_llm_happy_path(mock_import: Mock) -> None: + mock_ollama = get_mock_ollama() + mock_import.return_value = mock_ollama + mock_ollama.Client.return_value.chat.return_value = MagicMock( + message=MagicMock(content="ollama chat response"), + ) + llm = OllamaLLM(model_name="gpt") + + res = llm.invoke("my text") + assert isinstance(res, LLMResponse) + assert res.content == "ollama chat response" From c33f9c82ff7f086ff57558139e982adc5e0e4f9f Mon Sep 17 00:00:00 2001 From: Estelle Scifo Date: Thu, 12 Dec 2024 19:07:45 +0100 Subject: [PATCH 5/5] Text2Cypher custom prompt: doc, example and bug fix (#229) * Doc + bug fix * Do not change the behavior, just document they said * Use same order for patched functions and check order of mocked object --- docs/source/api.rst | 9 +++ examples/README.md | 5 +- .../retrievers/text2cypher_custom_prompt.py | 76 +++++++++++++++++++ examples/retrieve/text2cypher_search.py | 4 +- src/neo4j_graphrag/retrievers/text2cypher.py | 38 +++++----- tests/unit/retrievers/test_text2cypher.py | 35 ++++++++- 6 files changed, 139 insertions(+), 28 deletions(-) create mode 100644 examples/customize/retrievers/text2cypher_custom_prompt.py diff --git a/docs/source/api.rst b/docs/source/api.rst index 8e52f9a4..ca0647ee 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -338,12 +338,21 @@ RagTemplate .. autoclass:: neo4j_graphrag.generation.prompts.RagTemplate :members: + :exclude-members: format ERExtractionTemplate -------------------- .. autoclass:: neo4j_graphrag.generation.prompts.ERExtractionTemplate :members: + :exclude-members: format + +Text2CypherTemplate +-------------------- + +.. autoclass:: neo4j_graphrag.generation.prompts.Text2CypherTemplate + :members: + :exclude-members: format **** diff --git a/examples/README.md b/examples/README.md index 2faed5f8..a7308660 100644 --- a/examples/README.md +++ b/examples/README.md @@ -58,7 +58,8 @@ are listed in [the last section of this file](#customize). - [Control result format for VectorRetriever](customize/retrievers/result_formatter_vector_retriever.py) - [Control result format for VectorCypherRetriever](customize/retrievers/result_formatter_vector_cypher_retriever.py) - +- [Use pre-filters](customize/retrievers/use_pre_filters.py) +- [Text2Cypher: use a custom prompt](customize/retrievers/text2cypher_custom_prompt.py) ### LLMs @@ -74,7 +75,7 @@ are listed in [the last section of this file](#customize). ### Prompts -- [Using a custom prompt](old/graphrag_custom_prompt.py) +- [Using a custom prompt for RAG](customize/answer/custom_prompt.py) ### Embedders diff --git a/examples/customize/retrievers/text2cypher_custom_prompt.py b/examples/customize/retrievers/text2cypher_custom_prompt.py new file mode 100644 index 00000000..64ab5290 --- /dev/null +++ b/examples/customize/retrievers/text2cypher_custom_prompt.py @@ -0,0 +1,76 @@ +"""The example shows how to provide a custom prompt to Text2CypherRetriever. + +Example using the OpenAILLM, hence the OPENAI_API_KEY needs to be set in the +environment for this example to run. +""" + +import neo4j +from neo4j_graphrag.llm import OpenAILLM +from neo4j_graphrag.retrievers import Text2CypherRetriever +from neo4j_graphrag.schema import get_schema + +# Define database credentials +URI = "neo4j+s://demo.neo4jlabs.com" +AUTH = ("recommendations", "recommendations") +DATABASE = "recommendations" + +# Create LLM object +llm = OpenAILLM(model_name="gpt-4o", model_params={"temperature": 0}) + +# (Optional) Specify your own Neo4j schema +# (also see get_structured_schema and get_schema functions) +neo4j_schema = """ +Node properties: +User {name: STRING} +Person {name: STRING, born: INTEGER} +Movie {tagline: STRING, title: STRING, released: INTEGER} +Relationship properties: +ACTED_IN {roles: LIST} +DIRECTED {} +REVIEWED {summary: STRING, rating: INTEGER} +The relationships: +(:Person)-[:ACTED_IN]->(:Movie) +(:Person)-[:DIRECTED]->(:Movie) +(:User)-[:REVIEWED]->(:Movie) +""" + +prompt = """Task: Generate a Cypher statement for querying a Neo4j graph database from a user input. + +Do not use any properties or relationships not included in the schema. +Do not include triple backticks ``` or any additional text except the generated Cypher statement in your response. + +Always filter movies that have not already been reviewed by the user with name: '{user_name}' using for instance: +(m:Movie)<-[:REVIEWED]-(:User {{name: }}) + +Schema: +{schema} + +Input: +{query_text} + +Cypher query: +""" + +with neo4j.GraphDatabase.driver(URI, auth=AUTH) as driver: + # Initialize the retriever + retriever = Text2CypherRetriever( + driver=driver, + llm=llm, + neo4j_schema=neo4j_schema, + # here we provide a custom prompt + custom_prompt=prompt, + neo4j_database=DATABASE, + ) + + # Generate a Cypher query using the LLM, send it to the Neo4j database, and return the results + query_text = "Which movies did Hugo Weaving star in?" + print( + retriever.search( + query_text=query_text, + prompt_params={ + # you have to specify all placeholder except the {query_text} one + "schema": get_schema(driver), + "user_name": "the user asking question", + }, + ) + ) diff --git a/examples/retrieve/text2cypher_search.py b/examples/retrieve/text2cypher_search.py index e17cb65d..deb2f592 100644 --- a/examples/retrieve/text2cypher_search.py +++ b/examples/retrieve/text2cypher_search.py @@ -22,13 +22,11 @@ Movie {tagline: STRING, title: STRING, released: INTEGER} Relationship properties: ACTED_IN {roles: LIST} +DIRECTED {} REVIEWED {summary: STRING, rating: INTEGER} The relationships: (:Person)-[:ACTED_IN]->(:Movie) (:Person)-[:DIRECTED]->(:Movie) -(:Person)-[:PRODUCED]->(:Movie) -(:Person)-[:WROTE]->(:Movie) -(:Person)-[:FOLLOWS]->(:Person) (:Person)-[:REVIEWED]->(:Movie) """ diff --git a/src/neo4j_graphrag/retrievers/text2cypher.py b/src/neo4j_graphrag/retrievers/text2cypher.py index 039f42f0..fb0a3521 100644 --- a/src/neo4j_graphrag/retrievers/text2cypher.py +++ b/src/neo4j_graphrag/retrievers/text2cypher.py @@ -48,7 +48,7 @@ class Text2CypherRetriever(Retriever): """ Allows for the retrieval of records from a Neo4j database using natural language. Converts a user's natural language query to a Cypher query using an LLM, - then retrieves records from a Neo4j database using the generated Cypher query + then retrieves records from a Neo4j database using the generated Cypher query. Args: driver (neo4j.Driver): The Neo4j Python driver. @@ -98,23 +98,23 @@ def __init__( self.examples = validated_data.examples self.result_formatter = validated_data.result_formatter self.custom_prompt = validated_data.custom_prompt - try: + if validated_data.custom_prompt: + neo4j_schema = "" + else: if ( - not validated_data.custom_prompt - ): # don't need schema for a custom prompt - self.neo4j_schema = ( - validated_data.neo4j_schema_model.neo4j_schema - if validated_data.neo4j_schema_model - else get_schema(validated_data.driver_model.driver) - ) + validated_data.neo4j_schema_model + and validated_data.neo4j_schema_model.neo4j_schema + ): + neo4j_schema = validated_data.neo4j_schema_model.neo4j_schema else: - self.neo4j_schema = "" - - except (Neo4jError, DriverError) as e: - error_message = getattr(e, "message", str(e)) - raise SchemaFetchError( - f"Failed to fetch schema for Text2CypherRetriever: {error_message}" - ) from e + try: + neo4j_schema = get_schema(validated_data.driver_model.driver) + except (Neo4jError, DriverError) as e: + error_message = getattr(e, "message", str(e)) + raise SchemaFetchError( + f"Failed to fetch schema for Text2CypherRetriever: {error_message}" + ) from e + self.neo4j_schema = neo4j_schema def get_search_results( self, query_text: str, prompt_params: Optional[Dict[str, Any]] = None @@ -142,12 +142,10 @@ def get_search_results( if prompt_params is not None: # parse the schema and examples inputs - examples_to_use = prompt_params.get("examples") or ( + examples_to_use = prompt_params.pop("examples", None) or ( "\n".join(self.examples) if self.examples else "" ) - schema_to_use = prompt_params.get("schema") or self.neo4j_schema - prompt_params.pop("examples", None) - prompt_params.pop("schema", None) + schema_to_use = prompt_params.pop("schema", None) or self.neo4j_schema else: examples_to_use = "\n".join(self.examples) if self.examples else "" schema_to_use = self.neo4j_schema diff --git a/tests/unit/retrievers/test_text2cypher.py b/tests/unit/retrievers/test_text2cypher.py index 4d110c8e..05b1e545 100644 --- a/tests/unit/retrievers/test_text2cypher.py +++ b/tests/unit/retrievers/test_text2cypher.py @@ -19,6 +19,7 @@ from neo4j.exceptions import CypherSyntaxError, Neo4jError from neo4j_graphrag.exceptions import ( RetrieverInitializationError, + SchemaFetchError, SearchValidationError, Text2CypherRetrievalError, ) @@ -39,8 +40,8 @@ def test_t2c_retriever_initialization(driver: MagicMock, llm: MagicMock) -> None @patch("neo4j_graphrag.retrievers.base.Retriever._verify_version") @patch("neo4j_graphrag.retrievers.text2cypher.get_schema") def test_t2c_retriever_schema_retrieval( - _verify_version_mock: MagicMock, get_schema_mock: MagicMock, + _verify_version_mock: MagicMock, driver: MagicMock, llm: MagicMock, ) -> None: @@ -51,13 +52,13 @@ def test_t2c_retriever_schema_retrieval( @patch("neo4j_graphrag.retrievers.base.Retriever._verify_version") @patch("neo4j_graphrag.retrievers.text2cypher.get_schema") def test_t2c_retriever_schema_retrieval_failure( - _verify_version_mock: MagicMock, get_schema_mock: MagicMock, + _verify_version_mock: MagicMock, driver: MagicMock, llm: MagicMock, ) -> None: get_schema_mock.side_effect = Neo4jError - with pytest.raises(Neo4jError): + with pytest.raises(SchemaFetchError): Text2CypherRetriever(driver, llm) @@ -310,3 +311,31 @@ def test_t2c_retriever_with_custom_prompt_bad_prompt_params( llm.invoke.assert_called_once_with( """This is a custom prompt. test ['example A', 'example B']""" ) + + +@patch("neo4j_graphrag.retrievers.base.Retriever._verify_version") +@patch("neo4j_graphrag.retrievers.text2cypher.get_schema") +def test_t2c_retriever_with_custom_prompt_and_schema( + get_schema_mock: MagicMock, + _verify_version_mock: MagicMock, + driver: MagicMock, + llm: MagicMock, + neo4j_record: MagicMock, +) -> None: + prompt = "This is a custom prompt. {query_text} {schema}" + query = "test" + + driver.execute_query.return_value = ( + [neo4j_record], + None, + None, + ) + + retriever = Text2CypherRetriever(driver=driver, llm=llm, custom_prompt=prompt) + retriever.search( + query_text=query, + prompt_params={}, + ) + + get_schema_mock.assert_not_called() + llm.invoke.assert_called_once_with("""This is a custom prompt. test """)