From 63e49be1cf96ca4d5a2b670cd9f9fdad49a594a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Fri, 23 Aug 2024 18:19:10 -0600 Subject: [PATCH 01/14] feat: Support filesystem interfaces --- meltano.yml | 56 +++ poetry.lock | 840 +++++++++++++++++++---------------- pyproject.toml | 3 + tap_csv/client.py | 26 +- tap_csv/tap.py | 46 +- tap_csv/tests/test_client.py | 2 + 6 files changed, 582 insertions(+), 391 deletions(-) diff --git a/meltano.yml b/meltano.yml index 57e0343..9cb819f 100644 --- a/meltano.yml +++ b/meltano.yml @@ -18,7 +18,62 @@ plugins: keys: - col1 add_metadata_columns: false + settings_group_validation: + - [ftp.host] + - [github.org, github.repo] settings: + - name: filesystem + kind: options + options: + - label: Local Filesystem + value: local + - label: FTP + value: ftp + - label: GitHub + value: github + + # FTP settings + - name: ftp.host + label: FTP Host + description: Hostname of the FTP server + kind: string + - name: ftp.port + label: FTP Port + description: Port of the FTP server + kind: integer + - name: ftp.username + label: FTP Username + description: Username for the FTP server + kind: string + - name: ftp.password + label: FTP Password + description: Password for the FTP server + kind: string + sensitive: true + - name: ftp.encoding + label: FTP Encoding + description: Encoding for the FTP server + kind: string + + # GitHub settings + - name: github.org + label: GitHub Organization + description: Organization name on GitHub + kind: string + - name: github.repo + label: GitHub Repository + description: Repository name on GitHub + kind: string + - name: github.username + label: GitHub Username + description: Username for GitHub + kind: string + - name: github.token + label: GitHub Token + description: Token for GitHub + kind: string + sensitive: true + - name: files description: Array of objects containing keys - `entity`, `path`, `keys`, `encoding` (Optional), `delimiter` (Optional), `doublequote` (Optional), `escapechar` (Optional), `quotechar` (Optional), `skipinitialspace` (Optional), `strict` (Optional) kind: array @@ -30,6 +85,7 @@ plugins: - name: add_metadata_columns description: When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output. kind: boolean + loaders: - name: target-jsonl variant: andyh1203 diff --git a/poetry.lock b/poetry.lock index d722a1c..67d7aeb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,22 +13,22 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "backoff" @@ -302,13 +302,13 @@ toml = ["tomli"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -333,6 +333,45 @@ six = ">=1.10,<2.0" [package.extras] scandir = ["scandir (>=1.5,<2.0)"] +[[package]] +name = "fsspec" +version = "2024.6.1" +description = "File-system specification" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, + {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, +] + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +dev = ["pre-commit", "ruff"] +doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] +test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] +tqdm = ["tqdm"] + [[package]] name = "greenlet" version = "3.0.3" @@ -406,51 +445,55 @@ test = ["objgraph", "psutil"] [[package]] name = "idna" -version = "3.7" +version = "3.8" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, ] [[package]] name = "importlib-metadata" -version = "6.11.0" +version = "8.4.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"}, - {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"}, + {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, + {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.1" +version = "6.4.4" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, + {file = "importlib_resources-6.4.4-py3-none-any.whl", hash = "sha256:dda242603d1c9cd836c3368b1174ed74cb4049ecd209e7a1a0104620c18c5c11"}, + {file = "importlib_resources-6.4.4.tar.gz", hash = "sha256:20600c8b7361938dc0bb2d5ec0297802e575df486f5a544fa414da65e13721f7"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "inflection" @@ -476,13 +519,13 @@ files = [ [[package]] name = "joblib" -version = "1.3.2" +version = "1.4.2" description = "Lightweight pipelining with Python functions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"}, - {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"}, + {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, + {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, ] [[package]] @@ -501,13 +544,13 @@ ply = "*" [[package]] name = "jsonschema" -version = "4.21.1" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, - {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -520,7 +563,7 @@ rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -597,13 +640,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -681,73 +724,75 @@ cli = ["click (>=5.0)"] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "referencing" -version = "0.33.0" +version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [package.dependencies] @@ -756,13 +801,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.32.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, - {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -777,153 +822,158 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rpds-py" -version = "0.17.1" +version = "0.20.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.17.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d"}, - {file = "rpds_py-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59"}, - {file = "rpds_py-0.17.1-cp310-none-win32.whl", hash = "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d"}, - {file = "rpds_py-0.17.1-cp310-none-win_amd64.whl", hash = "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6"}, - {file = "rpds_py-0.17.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b"}, - {file = "rpds_py-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea"}, - {file = "rpds_py-0.17.1-cp311-none-win32.whl", hash = "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518"}, - {file = "rpds_py-0.17.1-cp311-none-win_amd64.whl", hash = "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf"}, - {file = "rpds_py-0.17.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf"}, - {file = "rpds_py-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23"}, - {file = "rpds_py-0.17.1-cp312-none-win32.whl", hash = "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1"}, - {file = "rpds_py-0.17.1-cp312-none-win_amd64.whl", hash = "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3"}, - {file = "rpds_py-0.17.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d"}, - {file = "rpds_py-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6"}, - {file = "rpds_py-0.17.1-cp38-none-win32.whl", hash = "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a"}, - {file = "rpds_py-0.17.1-cp38-none-win_amd64.whl", hash = "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb"}, - {file = "rpds_py-0.17.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a"}, - {file = "rpds_py-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b"}, - {file = "rpds_py-0.17.1-cp39-none-win32.whl", hash = "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f"}, - {file = "rpds_py-0.17.1-cp39-none-win_amd64.whl", hash = "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68"}, - {file = "rpds_py-0.17.1.tar.gz", hash = "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7"}, + {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, + {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, + {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, + {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, + {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, + {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, + {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, + {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, + {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, + {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, + {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, + {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, + {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, + {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, + {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, + {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, + {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, + {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, + {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, + {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, + {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, + {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, + {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, + {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, + {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, ] [[package]] name = "ruff" -version = "0.6.1" +version = "0.6.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, - {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, - {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, - {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, - {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, - {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, - {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, + {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, + {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, + {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, + {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, + {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, + {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, + {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, ] [[package]] name = "setuptools" -version = "70.0.0" +version = "73.0.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "setuptools-73.0.1-py3-none-any.whl", hash = "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e"}, + {file = "setuptools-73.0.1.tar.gz", hash = "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193"}, ] [package.extras] -docs = ["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"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +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)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] [[package]] name = "simpleeval" @@ -938,109 +988,121 @@ files = [ [[package]] name = "simplejson" -version = "3.19.2" +version = "3.19.3" description = "Simple, fast, extensible JSON encoder/decoder for Python" optional = false -python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" files = [ - {file = "simplejson-3.19.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3471e95110dcaf901db16063b2e40fb394f8a9e99b3fe9ee3acc6f6ef72183a2"}, - {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3194cd0d2c959062b94094c0a9f8780ffd38417a5322450a0db0ca1a23e7fbd2"}, - {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8a390e56a7963e3946ff2049ee1eb218380e87c8a0e7608f7f8790ba19390867"}, - {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1537b3dd62d8aae644f3518c407aa8469e3fd0f179cdf86c5992792713ed717a"}, - {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a8617625369d2d03766413bff9e64310feafc9fc4f0ad2b902136f1a5cd8c6b0"}, - {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:2c433a412e96afb9a3ce36fa96c8e61a757af53e9c9192c97392f72871e18e69"}, - {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f1c70249b15e4ce1a7d5340c97670a95f305ca79f376887759b43bb33288c973"}, - {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:287e39ba24e141b046812c880f4619d0ca9e617235d74abc27267194fc0c7835"}, - {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6f0a0b41dd05eefab547576bed0cf066595f3b20b083956b1405a6f17d1be6ad"}, - {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f98d918f7f3aaf4b91f2b08c0c92b1774aea113334f7cde4fe40e777114dbe6"}, - {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d74beca677623481810c7052926365d5f07393c72cbf62d6cce29991b676402"}, - {file = "simplejson-3.19.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7f2398361508c560d0bf1773af19e9fe644e218f2a814a02210ac2c97ad70db0"}, - {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ad331349b0b9ca6da86064a3599c425c7a21cd41616e175ddba0866da32df48"}, - {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:332c848f02d71a649272b3f1feccacb7e4f7e6de4a2e6dc70a32645326f3d428"}, - {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25785d038281cd106c0d91a68b9930049b6464288cea59ba95b35ee37c2d23a5"}, - {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18955c1da6fc39d957adfa346f75226246b6569e096ac9e40f67d102278c3bcb"}, - {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:11cc3afd8160d44582543838b7e4f9aa5e97865322844b75d51bf4e0e413bb3e"}, - {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b01fda3e95d07a6148702a641e5e293b6da7863f8bc9b967f62db9461330562c"}, - {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:778331444917108fa8441f59af45886270d33ce8a23bfc4f9b192c0b2ecef1b3"}, - {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9eb117db8d7ed733a7317c4215c35993b815bf6aeab67523f1f11e108c040672"}, - {file = "simplejson-3.19.2-cp310-cp310-win32.whl", hash = "sha256:39b6d79f5cbfa3eb63a869639cfacf7c41d753c64f7801efc72692c1b2637ac7"}, - {file = "simplejson-3.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:5675e9d8eeef0aa06093c1ff898413ade042d73dc920a03e8cea2fb68f62445a"}, - {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed628c1431100b0b65387419551e822987396bee3c088a15d68446d92f554e0c"}, - {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:adcb3332979cbc941b8fff07181f06d2b608625edc0a4d8bc3ffc0be414ad0c4"}, - {file = "simplejson-3.19.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08889f2f597ae965284d7b52a5c3928653a9406d88c93e3161180f0abc2433ba"}, - {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef7938a78447174e2616be223f496ddccdbf7854f7bf2ce716dbccd958cc7d13"}, - {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a970a2e6d5281d56cacf3dc82081c95c1f4da5a559e52469287457811db6a79b"}, - {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554313db34d63eac3b3f42986aa9efddd1a481169c12b7be1e7512edebff8eaf"}, - {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d36081c0b1c12ea0ed62c202046dca11438bee48dd5240b7c8de8da62c620e9"}, - {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a3cd18e03b0ee54ea4319cdcce48357719ea487b53f92a469ba8ca8e39df285e"}, - {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66e5dc13bfb17cd6ee764fc96ccafd6e405daa846a42baab81f4c60e15650414"}, - {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:972a7833d4a1fcf7a711c939e315721a88b988553fc770a5b6a5a64bd6ebeba3"}, - {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3e74355cb47e0cd399ead3477e29e2f50e1540952c22fb3504dda0184fc9819f"}, - {file = "simplejson-3.19.2-cp311-cp311-win32.whl", hash = "sha256:1dd4f692304854352c3e396e9b5f0a9c9e666868dd0bdc784e2ac4c93092d87b"}, - {file = "simplejson-3.19.2-cp311-cp311-win_amd64.whl", hash = "sha256:9300aee2a8b5992d0f4293d88deb59c218989833e3396c824b69ba330d04a589"}, - {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b8d940fd28eb34a7084877747a60873956893e377f15a32ad445fe66c972c3b8"}, - {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4969d974d9db826a2c07671273e6b27bc48e940738d768fa8f33b577f0978378"}, - {file = "simplejson-3.19.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c594642d6b13d225e10df5c16ee15b3398e21a35ecd6aee824f107a625690374"}, - {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2f5a398b5e77bb01b23d92872255e1bcb3c0c719a3be40b8df146570fe7781a"}, - {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176a1b524a3bd3314ed47029a86d02d5a95cc0bee15bd3063a1e1ec62b947de6"}, - {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3c7363a8cb8c5238878ec96c5eb0fc5ca2cb11fc0c7d2379863d342c6ee367a"}, - {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:346820ae96aa90c7d52653539a57766f10f33dd4be609206c001432b59ddf89f"}, - {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de9a2792612ec6def556d1dc621fd6b2073aff015d64fba9f3e53349ad292734"}, - {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1c768e7584c45094dca4b334af361e43b0aaa4844c04945ac7d43379eeda9bc2"}, - {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:9652e59c022e62a5b58a6f9948b104e5bb96d3b06940c6482588176f40f4914b"}, - {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9c1a4393242e321e344213a90a1e3bf35d2f624aa8b8f6174d43e3c6b0e8f6eb"}, - {file = "simplejson-3.19.2-cp312-cp312-win32.whl", hash = "sha256:7cb98be113911cb0ad09e5523d0e2a926c09a465c9abb0784c9269efe4f95917"}, - {file = "simplejson-3.19.2-cp312-cp312-win_amd64.whl", hash = "sha256:6779105d2fcb7fcf794a6a2a233787f6bbd4731227333a072d8513b252ed374f"}, - {file = "simplejson-3.19.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:061e81ea2d62671fa9dea2c2bfbc1eec2617ae7651e366c7b4a2baf0a8c72cae"}, - {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4280e460e51f86ad76dc456acdbfa9513bdf329556ffc8c49e0200878ca57816"}, - {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11c39fbc4280d7420684494373b7c5904fa72a2b48ef543a56c2d412999c9e5d"}, - {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bccb3e88ec26ffa90f72229f983d3a5d1155e41a1171190fa723d4135523585b"}, - {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb5b50dc6dd671eb46a605a3e2eb98deb4a9af787a08fcdddabe5d824bb9664"}, - {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d94245caa3c61f760c4ce4953cfa76e7739b6f2cbfc94cc46fff6c050c2390c5"}, - {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0e5ffc763678d48ecc8da836f2ae2dd1b6eb2d27a48671066f91694e575173c"}, - {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d222a9ed082cd9f38b58923775152003765016342a12f08f8c123bf893461f28"}, - {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8434dcdd347459f9fd9c526117c01fe7ca7b016b6008dddc3c13471098f4f0dc"}, - {file = "simplejson-3.19.2-cp36-cp36m-win32.whl", hash = "sha256:c9ac1c2678abf9270e7228133e5b77c6c3c930ad33a3c1dfbdd76ff2c33b7b50"}, - {file = "simplejson-3.19.2-cp36-cp36m-win_amd64.whl", hash = "sha256:92c4a4a2b1f4846cd4364855cbac83efc48ff5a7d7c06ba014c792dd96483f6f"}, - {file = "simplejson-3.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0d551dc931638e2102b8549836a1632e6e7cf620af3d093a7456aa642bff601d"}, - {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73a8a4653f2e809049999d63530180d7b5a344b23a793502413ad1ecea9a0290"}, - {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40847f617287a38623507d08cbcb75d51cf9d4f9551dd6321df40215128325a3"}, - {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be893258d5b68dd3a8cba8deb35dc6411db844a9d35268a8d3793b9d9a256f80"}, - {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9eb3cff1b7d71aa50c89a0536f469cb8d6dcdd585d8f14fb8500d822f3bdee4"}, - {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d0f402e787e6e7ee7876c8b05e2fe6464820d9f35ba3f172e95b5f8b699f6c7f"}, - {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbbcc6b0639aa09b9649f36f1bcb347b19403fe44109948392fbb5ea69e48c3e"}, - {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2fc697be37585eded0c8581c4788fcfac0e3f84ca635b73a5bf360e28c8ea1a2"}, - {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b0a3eb6dd39cce23801a50c01a0976971498da49bc8a0590ce311492b82c44b"}, - {file = "simplejson-3.19.2-cp37-cp37m-win32.whl", hash = "sha256:49f9da0d6cd17b600a178439d7d2d57c5ef01f816b1e0e875e8e8b3b42db2693"}, - {file = "simplejson-3.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c87c22bd6a987aca976e3d3e23806d17f65426191db36d40da4ae16a6a494cbc"}, - {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e4c166f743bb42c5fcc60760fb1c3623e8fda94f6619534217b083e08644b46"}, - {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a48679310e1dd5c9f03481799311a65d343748fe86850b7fb41df4e2c00c087"}, - {file = "simplejson-3.19.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0521e0f07cb56415fdb3aae0bbd8701eb31a9dfef47bb57206075a0584ab2a2"}, - {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d2d5119b1d7a1ed286b8af37357116072fc96700bce3bec5bb81b2e7057ab41"}, - {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c1467d939932901a97ba4f979e8f2642415fcf02ea12f53a4e3206c9c03bc17"}, - {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49aaf4546f6023c44d7e7136be84a03a4237f0b2b5fb2b17c3e3770a758fc1a0"}, - {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60848ab779195b72382841fc3fa4f71698a98d9589b0a081a9399904487b5832"}, - {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0436a70d8eb42bea4fe1a1c32d371d9bb3b62c637969cb33970ad624d5a3336a"}, - {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:49e0e3faf3070abdf71a5c80a97c1afc059b4f45a5aa62de0c2ca0444b51669b"}, - {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ff836cd4041e16003549449cc0a5e372f6b6f871eb89007ab0ee18fb2800fded"}, - {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3848427b65e31bea2c11f521b6fc7a3145d6e501a1038529da2391aff5970f2f"}, - {file = "simplejson-3.19.2-cp38-cp38-win32.whl", hash = "sha256:3f39bb1f6e620f3e158c8b2eaf1b3e3e54408baca96a02fe891794705e788637"}, - {file = "simplejson-3.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:0405984f3ec1d3f8777c4adc33eac7ab7a3e629f3b1c05fdded63acc7cf01137"}, - {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:445a96543948c011a3a47c8e0f9d61e9785df2544ea5be5ab3bc2be4bd8a2565"}, - {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a8c3cc4f9dfc33220246760358c8265dad6e1104f25f0077bbca692d616d358"}, - {file = "simplejson-3.19.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af9c7e6669c4d0ad7362f79cb2ab6784d71147503e62b57e3d95c4a0f222c01c"}, - {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:064300a4ea17d1cd9ea1706aa0590dcb3be81112aac30233823ee494f02cb78a"}, - {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9453419ea2ab9b21d925d0fd7e3a132a178a191881fab4169b6f96e118cc25bb"}, - {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e038c615b3906df4c3be8db16b3e24821d26c55177638ea47b3f8f73615111c"}, - {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16ca9c90da4b1f50f089e14485db8c20cbfff2d55424062791a7392b5a9b3ff9"}, - {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1018bd0d70ce85f165185d2227c71e3b1e446186f9fa9f971b69eee223e1e3cd"}, - {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e8dd53a8706b15bc0e34f00e6150fbefb35d2fd9235d095b4f83b3c5ed4fa11d"}, - {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2d022b14d7758bfb98405672953fe5c202ea8a9ccf9f6713c5bd0718eba286fd"}, - {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:febffa5b1eda6622d44b245b0685aff6fb555ce0ed734e2d7b1c3acd018a2cff"}, - {file = "simplejson-3.19.2-cp39-cp39-win32.whl", hash = "sha256:4edcd0bf70087b244ba77038db23cd98a1ace2f91b4a3ecef22036314d77ac23"}, - {file = "simplejson-3.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:aad7405c033d32c751d98d3a65801e2797ae77fac284a539f6c3a3e13005edc4"}, - {file = "simplejson-3.19.2-py3-none-any.whl", hash = "sha256:bcedf4cae0d47839fee7de344f96b5694ca53c786f28b5f773d4f0b265a159eb"}, - {file = "simplejson-3.19.2.tar.gz", hash = "sha256:9eb442a2442ce417801c912df68e1f6ccfcd41577ae7274953ab3ad24ef7d82c"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f39caec26007a2d0efab6b8b1d74873ede9351962707afab622cc2285dd26ed0"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:83c87706265ae3028e8460d08b05f30254c569772e859e5ba61fe8af2c883468"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0b5ddd2c7d1d3f4d23224bc8a04bbf1430ae9a8149c05b90f8fc610f7f857a23"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ad0e0b1ce9bd3edb5cf64b5b5b76eacbfdac8c5367153aeeec8a8b1407f68342"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:93be280fc69a952c76e261036312c20b910e7fa9e234f1d89bdfe3fa34f8a023"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6d43e24b88c80f997081503f693be832fc90854f278df277dd54f8a4c847ab61"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2876027ebdd599d730d36464debe84619b0368e9a642ca6e7c601be55aed439e"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:0766ca6222b410e08e0053a0dda3606cafb3973d5d00538307f631bb59743396"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50d8b742d74c449c4dcac570d08ce0f21f6a149d2d9cf7652dbf2ba9a1bc729a"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd011fc3c1d88b779645495fdb8189fb318a26981eebcce14109460e062f209b"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:637c4d4b81825c1f4d651e56210bd35b5604034b192b02d2d8f17f7ce8c18f42"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f56eb03bc9e432bb81adc8ecff2486d39feb371abb442964ffb44f6db23b332"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef59a53be400c1fad2c914b8d74c9d42384fed5174f9321dd021b7017fd40270"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72e8abbc86fcac83629a030888b45fed3a404d54161118be52cb491cd6975d3e"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8efb03ca77bd7725dfacc9254df00d73e6f43013cf39bd37ef1a8ed0ebb5165"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:add8850db04b98507a8b62d248a326ecc8561e6d24336d1ca5c605bbfaab4cad"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fc3dc9fb413fc34c396f52f4c87de18d0bd5023804afa8ab5cc224deeb6a9900"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dfa420bb9225dd33b6efdabde7c6a671b51150b9b1d9c4e5cd74d3b420b3fe1"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7b5c472099b39b274dcde27f1113db8d818c9aa3ba8f78cbb8ad04a4c1ac2118"}, + {file = "simplejson-3.19.3-cp310-cp310-win32.whl", hash = "sha256:817abad79241ed4a507b3caf4d3f2be5079f39d35d4c550a061988986bffd2ec"}, + {file = "simplejson-3.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:dd5b9b1783e14803e362a558680d88939e830db2466f3fa22df5c9319f8eea94"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e88abff510dcff903a18d11c2a75f9964e768d99c8d147839913886144b2065e"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:934a50a614fb831614db5dbfba35127ee277624dda4d15895c957d2f5d48610c"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:212fce86a22188b0c7f53533b0f693ea9605c1a0f02c84c475a30616f55a744d"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d9e8f836688a8fabe6a6b41b334aa550a6823f7b4ac3d3712fc0ad8655be9a8"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23228037dc5d41c36666384062904d74409a62f52283d9858fa12f4c22cffad1"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0791f64fed7d4abad639491f8a6b1ba56d3c604eb94b50f8697359b92d983f36"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f614581b61a26fbbba232a1391f6cee82bc26f2abbb6a0b44a9bba25c56a1c"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1df0aaf1cb787fdf34484ed4a1f0c545efd8811f6028623290fef1a53694e597"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:951095be8d4451a7182403354c22ec2de3e513e0cc40408b689af08d02611588"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a954b30810988feeabde843e3263bf187697e0eb5037396276db3612434049b"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c40df31a75de98db2cdfead6074d4449cd009e79f54c1ebe5e5f1f153c68ad20"}, + {file = "simplejson-3.19.3-cp311-cp311-win32.whl", hash = "sha256:7e2a098c21ad8924076a12b6c178965d88a0ad75d1de67e1afa0a66878f277a5"}, + {file = "simplejson-3.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:c9bedebdc5fdad48af8783022bae307746d54006b783007d1d3c38e10872a2c6"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:66a0399e21c2112acacfebf3d832ebe2884f823b1c7e6d1363f2944f1db31a99"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6ef9383c5e05f445be60f1735c1816163c874c0b1ede8bb4390aff2ced34f333"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42e5acf80d4d971238d4df97811286a044d720693092b20a56d5e56b7dcc5d09"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0b0efc7279d768db7c74d3d07f0b5c81280d16ae3fb14e9081dc903e8360771"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0552eb06e7234da892e1d02365cd2b7b2b1f8233aa5aabdb2981587b7cc92ea0"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf6a3b9a7d7191471b464fe38f684df10eb491ec9ea454003edb45a011ab187"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7017329ca8d4dca94ad5e59f496e5fc77630aecfc39df381ffc1d37fb6b25832"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67a20641afebf4cfbcff50061f07daad1eace6e7b31d7622b6fa2c40d43900ba"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd6a7dabcc4c32daf601bc45e01b79175dde4b52548becea4f9545b0a4428169"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:08f9b443a94e72dd02c87098c96886d35790e79e46b24e67accafbf13b73d43b"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa97278ae6614346b5ca41a45a911f37a3261b57dbe4a00602048652c862c28b"}, + {file = "simplejson-3.19.3-cp312-cp312-win32.whl", hash = "sha256:ef28c3b328d29b5e2756903aed888960bc5df39b4c2eab157ae212f70ed5bf74"}, + {file = "simplejson-3.19.3-cp312-cp312-win_amd64.whl", hash = "sha256:1e662336db50ad665777e6548b5076329a94a0c3d4a0472971c588b3ef27de3a"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0959e6cb62e3994b5a40e31047ff97ef5c4138875fae31659bead691bed55896"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a7bfad839c624e139a4863007233a3f194e7c51551081f9789cba52e4da5167"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afab2f7f2486a866ff04d6d905e9386ca6a231379181a3838abce1f32fbdcc37"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00313681015ac498e1736b304446ee6d1c72c5b287cd196996dad84369998f7"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d936ae682d5b878af9d9eb4d8bb1fdd5e41275c8eb59ceddb0aeed857bb264a2"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c6657485393f2e9b8177c77a7634f13ebe70d5e6de150aae1677d91516ce6b"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a6a750d3c7461b1c47cfc6bba8d9e57a455e7c5f80057d2a82f738040dd1129"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ea7a4a998c87c5674a27089e022110a1a08a7753f21af3baf09efe9915c23c3c"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6300680d83a399be2b8f3b0ef7ef90b35d2a29fe6e9c21438097e0938bbc1564"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ab69f811a660c362651ae395eba8ce84f84c944cea0df5718ea0ba9d1e4e7252"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:256e09d0f94d9c3d177d9e95fd27a68c875a4baa2046633df387b86b652f5747"}, + {file = "simplejson-3.19.3-cp313-cp313-win32.whl", hash = "sha256:2c78293470313aefa9cfc5e3f75ca0635721fb016fb1121c1c5b0cb8cc74712a"}, + {file = "simplejson-3.19.3-cp313-cp313-win_amd64.whl", hash = "sha256:3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c"}, + {file = "simplejson-3.19.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:89b35433186e977fa86ff1fd179c1fadff39cfa3afa1648dab0b6ca53153acd9"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d43c2d7504eda566c50203cdc9dc043aff6f55f1b7dae0dcd79dfefef9159d1c"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6890ff9cf0bd2e1d487e2a8869ebd620a44684c0a9667fa5ee751d099d5d84c8"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1069143a8fb3905e1bc0696c62be7e3adf812e9f1976ac9ae15b05112ff57cc9"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb324bb903330cbb35d87cce367a12631cd5720afa06e5b9c906483970946da6"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:0a32859d45d7b85fb803bb68f6bee14526991a1190269116c33399fa0daf9bbf"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:23833ee7e791ec968b744dfee2a2d39df7152050051096caf4296506d75608d8"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:d73efb03c5b39249c82488a994f0998f9e4399e3d085209d2120503305ba77a8"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7923878b7a0142d39763ec2dbecff3053c1bedd3653585a8474666e420fe83f5"}, + {file = "simplejson-3.19.3-cp36-cp36m-win32.whl", hash = "sha256:7355c7203353c36d46c4e7b6055293b3d2be097bbc5e2874a2b8a7259f0325dd"}, + {file = "simplejson-3.19.3-cp36-cp36m-win_amd64.whl", hash = "sha256:d1b8b4d6379fe55f471914345fe6171d81a18649dacf3248abfc9c349b4442eb"}, + {file = "simplejson-3.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d36608557b4dcd7a62c29ad4cd7c5a1720bbf7dc942eff9dc42d2c542a5f042d"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7137e69c6781ecf23afab064be94a277236c9cba31aa48ff1a0ec3995c69171e"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76f8c28fe2d426182405b18ddf3001fce47835a557dc15c3d8bdea01c03361da"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff7bc1bbdaa3e487c9469128bf39408e91f5573901cb852e03af378d3582c52d"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0782cb9bf827f0c488b6aa0f2819f618308a3caf2973cfd792e45d631bec4db"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:6fea0716c593dabb4392c4996d4e902a83b2428e6da82938cf28a523a11eb277"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:8f41bb5370b34f63171e65fdb00e12be1d83675cecb23e627df26f4c88dfc021"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:37105d1d708365b91165e1a6e505bdecc88637091348cf4b6adcdcb4f5a5fb8b"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:b9198c1f1f8910a3b86b60f4fe2556d9d28d3fefe35bffe6be509a27402e694d"}, + {file = "simplejson-3.19.3-cp37-cp37m-win32.whl", hash = "sha256:bc164f32dd9691e7082ce5df24b4cf8c6c394bbf9bdeeb5d843127cd07ab8ad2"}, + {file = "simplejson-3.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1bd41f2cb1a2c57656ceff67b12d005cb255c728265e222027ad73193a04005a"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0733ecd95ae03ae718ec74aad818f5af5f3155d596f7b242acbc1621e765e5fb"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a0710d1a5e41c4f829caa1572793dd3130c8d65c2b194c24ff29c4c305c26e0"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a53a07320c5ff574d8b1a89c937ce33608832f166f39dff0581ac43dc979abd"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1773cabfba66a6337b547e45dafbd471b09487370bcab75bd28f626520410d29"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c0104b4b7d2c75ccedbf1d9d5a3bd2daa75e51053935a44ba012e2fd4c43752"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c49eeb94b8f09dc8a5843c156a22b8bde6aa1ddc65ca8ddc62dddcc001e6a2d"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dc5c1a85ff388e98ea877042daec3d157b6db0d85bac6ba5498034689793e7e"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:49549e3d81ab4a58424405aa545602674d8c35c20e986b42bb8668e782a94bac"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:e1a1452ad5723ff129b081e3c8aa4ba56b8734fee4223355ed7b815a7ece69bc"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:d0d5a63f1768fed7e78cf55712dee81f5a345e34d34224f3507ebf71df2b754d"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7e062767ac165df9a46963f5735aa4eee0089ec1e48b3f2ec46182754b96f55e"}, + {file = "simplejson-3.19.3-cp38-cp38-win32.whl", hash = "sha256:56134bbafe458a7b21f6fddbf889d36bec6d903718f4430768e3af822f8e27c2"}, + {file = "simplejson-3.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:bcde83a553a96dc7533736c547bddaa35414a2566ab0ecf7d3964fc4bdb84c11"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b5587feda2b65a79da985ae6d116daf6428bf7489992badc29fc96d16cd27b05"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0d2b00ecbcd1a3c5ea1abc8bb99a26508f758c1759fd01c3be482a3655a176f"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32a3ada8f3ea41db35e6d37b86dade03760f804628ec22e4fe775b703d567426"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f455672f4738b0f47183c5896e3606cd65c9ddee3805a4d18e8c96aa3f47c84"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b737a5fefedb8333fa50b8db3dcc9b1d18fd6c598f89fa7debff8b46bf4e511"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb47ee773ce67476a960e2db4a0a906680c54f662521550828c0cc57d0099426"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eed8cd98a7b24861da9d3d937f5fbfb6657350c547528a117297fe49e3960667"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:619756f1dd634b5bdf57d9a3914300526c3b348188a765e45b8b08eabef0c94e"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dd7230d061e755d60a4d5445bae854afe33444cdb182f3815cff26ac9fb29a15"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:101a3c8392028cd704a93c7cba8926594e775ca3c91e0bee82144e34190903f1"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e557712fc79f251673aeb3fad3501d7d4da3a27eff0857af2e1d1afbbcf6685"}, + {file = "simplejson-3.19.3-cp39-cp39-win32.whl", hash = "sha256:0bc5544e3128891bf613b9f71813ee2ec9c11574806f74dd8bb84e5e95bf64a2"}, + {file = "simplejson-3.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:06662392e4913dc8846d6a71a6d5de86db5fba244831abe1dd741d62a4136764"}, + {file = "simplejson-3.19.3-py3-none-any.whl", hash = "sha256:49cc4c7b940d43bd12bf87ec63f28cbc4964fc4e12c031cc8cd01650f43eb94e"}, + {file = "simplejson-3.19.3.tar.gz", hash = "sha256:8e086896c36210ab6050f2f9f095a5f1e03c83fa0e7f296d6cba425411364680"}, ] [[package]] @@ -1097,64 +1159,64 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.25" +version = "2.0.32" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win32.whl", hash = "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win_amd64.whl", hash = "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win32.whl", hash = "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win32.whl", hash = "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win_amd64.whl", hash = "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win32.whl", hash = "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win_amd64.whl", hash = "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win32.whl", hash = "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win_amd64.whl", hash = "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win32.whl", hash = "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win_amd64.whl", hash = "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7"}, - {file = "SQLAlchemy-2.0.25-py3-none-any.whl", hash = "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3"}, - {file = "SQLAlchemy-2.0.25.tar.gz", hash = "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-win32.whl", hash = "sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-win32.whl", hash = "sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-win32.whl", hash = "sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-win_amd64.whl", hash = "sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-win32.whl", hash = "sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-win32.whl", hash = "sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-win32.whl", hash = "sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84"}, + {file = "SQLAlchemy-2.0.32-py3-none-any.whl", hash = "sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202"}, + {file = "SQLAlchemy-2.0.32.tar.gz", hash = "sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -1220,15 +1282,33 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "universal-pathlib" +version = "0.2.3" +description = "pathlib api extended to use fsspec backends" +optional = false +python-versions = ">=3.8" +files = [ + {file = "universal_pathlib-0.2.3-py3-none-any.whl", hash = "sha256:4e0f6f85ca7ce66aec866a9c5f32d4a081858d2e58c70a6be84fb2df1f2806d3"}, + {file = "universal_pathlib-0.2.3.tar.gz", hash = "sha256:22f5f289fedec4b663956596742652e2177bca24661b6c8a173f5974cfee0052"}, ] +[package.dependencies] +fsspec = ">=2022.1.0,<2024.3.1 || >2024.3.1" + +[package.extras] +dev = ["adlfs", "aiohttp", "cheroot", "gcsfs", "moto[s3,server] (<5)", "mypy (==1.10.0)", "packaging", "pydantic", "pydantic-settings", "pylint (==2.17.4)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-mock (==3.12.0)", "pytest-mypy-plugins (==3.1.2)", "pytest-sugar (==0.9.7)", "requests", "s3fs", "smbprotocol", "webdav4[fsspec]", "wsgidav"] +tests = ["mypy (==1.10.0)", "packaging", "pylint (==2.17.4)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-mock (==3.12.0)", "pytest-mypy-plugins (==3.1.2)", "pytest-sugar (==0.9.7)"] + [[package]] name = "urllib3" version = "1.26.19" @@ -1247,20 +1327,20 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "zipp" -version = "3.19.1" +version = "3.20.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, - {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, + {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, + {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, ] [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.8" -content-hash = "982c9acd51960d33eb0d18d6e8df7b144132b0098e8cfd26f176df81f1123737" +content-hash = "af8ac6ac1330c9d88b1f2e4a8ad09c21317b954f75128c4e3ea971e5ce7620fc" diff --git a/pyproject.toml b/pyproject.toml index fe5945d..0e5f5a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,9 @@ license = "Apache-2.0" [tool.poetry.dependencies] python = ">=3.8" +fsspec = "~=2024.6.1" singer-sdk = "~=0.39.0" +universal-pathlib = "~=0.2.3" [tool.poetry.group.dev.dependencies] coverage = ">=7.2" @@ -40,6 +42,7 @@ ignore = [ "D213", ] select = [ + "F", "A", "B", "W", diff --git a/tap_csv/client.py b/tap_csv/client.py index cae3892..e155e0e 100644 --- a/tap_csv/client.py +++ b/tap_csv/client.py @@ -5,8 +5,8 @@ import csv import os import typing as t -from datetime import datetime, timezone +import fsspec from singer_sdk import typing as th from singer_sdk.streams import Stream @@ -24,10 +24,11 @@ class CSVStream(Stream): file_paths: list[str] = [] # noqa: RUF012 header: list[str] = [] # noqa: RUF012 - def __init__(self, *args, **kwargs): + def __init__(self, filesystem: str, *args, options: dict[str, t.Any], **kwargs): """Init CSVStram.""" # cache file_config so we dont need to go iterating the config list again later self.file_config = kwargs.pop("file_config") + self.fs = fsspec.filesystem(filesystem, **options) super().__init__(*args, **kwargs) def get_records(self, context: Context | None) -> t.Iterable[dict]: @@ -38,9 +39,15 @@ def get_records(self, context: Context | None) -> t.Iterable[dict]: require partitioning and should ignore the `context` argument. """ for file_path in self.get_file_paths(): - file_last_modified = datetime.fromtimestamp( - os.path.getmtime(file_path), timezone.utc - ) + self.logger.info("Reading file at %s", file_path) + try: + file_last_modified = self.fs.modified(file_path) + except NotImplementedError: + self.logger.warning( + "Filesystem implementation for %s does not support modified time, skipping", + self.fs.protocol, + ) + file_last_modified = None file_lineno = -1 @@ -58,7 +65,7 @@ def get_records(self, context: Context | None) -> t.Iterable[dict]: def _get_recursive_file_paths(self, file_path: str) -> list: file_paths = [] - for dirpath, _, filenames in os.walk(file_path): + for dirpath, _, filenames in self.fs.walk(file_path): for filename in filenames: file_path = os.path.join(dirpath, filename) if self.is_valid_filename(file_path): @@ -77,13 +84,14 @@ def get_file_paths(self) -> list: return self.file_paths file_path = self.file_config["path"] - if not os.path.exists(file_path): + if not self.fs.exists(file_path): raise Exception(f"File path does not exist {file_path}") file_paths = [] - if os.path.isdir(file_path): + if self.fs.isdir(file_path): clean_file_path = os.path.normpath(file_path) + os.sep file_paths = self._get_recursive_file_paths(clean_file_path) + elif self.is_valid_filename(file_path): file_paths.append(file_path) @@ -118,7 +126,7 @@ def get_rows(self, file_path: str) -> t.Iterable[list]: skipinitialspace=self.file_config.get("skipinitialspace", False), strict=self.file_config.get("strict", False), ) - with open(file_path, encoding=encoding) as f: + with self.fs.open(file_path, mode="r", encoding=encoding) as f: yield from csv.reader(f, dialect="tap_dialect") @property diff --git a/tap_csv/tap.py b/tap_csv/tap.py index 5508a40..9ff0dc2 100644 --- a/tap_csv/tap.py +++ b/tap_csv/tap.py @@ -4,10 +4,10 @@ import json import os -from typing import List from singer_sdk import Stream, Tap from singer_sdk import typing as th # JSON schema typing helpers +from singer_sdk.exceptions import ConfigValidationError from singer_sdk.helpers._classproperty import classproperty from singer_sdk.helpers.capabilities import TapCapabilities @@ -20,6 +20,37 @@ class TapCSV(Tap): name = "tap-csv" config_jsonschema = th.PropertiesList( + th.Property( + "filesystem", + th.StringType, + required=False, + default="local", + description="The filesystem to use for reading files.", + allowed_values=[ + "local", + "ftp", + "github", + ], + ), + th.Property( + "ftp", + th.ObjectType( + th.Property("host", th.StringType, required=True), + th.Property("port", th.IntegerType, default=21), + th.Property("username", th.StringType), + th.Property("password", th.StringType, secret=True), + th.Property("encoding", th.StringType, default="utf-8"), + ), + ), + th.Property( + "github", + th.ObjectType( + th.Property("org", th.StringType, required=True), + th.Property("repo", th.StringType, required=True), + th.Property("username", th.StringType, required=False), + th.Property("token", th.StringType, required=False, secret=True), + ), + ), th.Property( "files", th.ArrayType( @@ -59,7 +90,7 @@ class TapCSV(Tap): @classproperty def capabilities(self) -> list[TapCapabilities]: - """Get tap capabilites.""" + """Get tap capabilities.""" return [ TapCapabilities.CATALOG, TapCapabilities.DISCOVER, @@ -87,11 +118,22 @@ def get_file_configs(self) -> list[dict]: def discover_streams(self) -> list[Stream]: """Return a list of discovered streams.""" + filesystem = self.config["filesystem"] + + if filesystem != "local" and filesystem not in self.config: + error_message = f"Missing filesystem options for {filesystem}" + raise ConfigValidationError( + "Misconfigured filesystem", + errors=[error_message], + ) + return [ CSVStream( tap=self, name=file_config.get("entity"), file_config=file_config, + filesystem=filesystem, + options=self.config.get(filesystem, {}), ) for file_config in self.get_file_configs() ] diff --git a/tap_csv/tests/test_client.py b/tap_csv/tests/test_client.py index cc597d9..e14326e 100644 --- a/tap_csv/tests/test_client.py +++ b/tap_csv/tests/test_client.py @@ -25,6 +25,8 @@ def test_get_file_paths_recursively(): tap=TapCSV(config=SAMPLE_CONFIG, catalog={}, state={}), name="test_recursive", file_config=SAMPLE_CONFIG.get("files")[0], + filesystem="local", + options={}, ) assert stream.get_file_paths() == [ f"{test_data_dir}/data/subfolder1/alphabet.csv", From 7a59470fa9eee206af2fb81fd7f93568c3e79475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Tue, 3 Sep 2024 09:38:55 -0600 Subject: [PATCH 02/14] Update settings docs --- README.md | 36 +++++++++++++--- tap_csv/tap.py | 111 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 39bbe35..eff7008 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,23 @@ Note: This tap currently does not support incremental state. ## Settings -| Setting | Required | Default | Description | -|:--------------------|:--------:|:-------:|:------------| -| files | False | None | An array of csv file stream settings. | -| csv_files_definition| False | None | A path to the JSON file holding an array of file settings. | -| add_metadata_columns| False | False | When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output. | +| Setting | Required | Default | Description | +| :------------------- | :------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| files | False | None | An array of csv file stream settings | +| filesystem | False | local | The filesystem to use for reading files | +| ftp | False | None | FTP connection settings | +| ftp.host | True | None | FTP server host | +| ftp.port | False | 21 | FTP server port | +| ftp.username | False | None | FTP username | +| ftp.password | False | None | FTP password | +| ftp.encoding | False | utf-8 | FTP server encoding | +| github | False | None | GitHub connection settings | +| github.org | True | None | GitHub organization or user where the repository is located | +| github.repo | True | None | GitHub repository | +| github.username | False | None | GitHub username | +| github.token | False | None | GitHub token | +| csv_files_definition | False | None | A path to the JSON file holding an array of file settings | +| add_metadata_columns | False | 0 | When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output | A full list of supported settings and capabilities is available by running: `tap-csv --about` @@ -81,6 +93,20 @@ Optionally, the files definition can be provided by an external json file: ] ``` +### Built-in Singer SDK settings + +The following settings are supported by the Singer SDK and are automatically handled by the tap: + +| Setting | Required | Default | Description | +| :------------------- | :------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| stream_maps | False | None | Config object for stream maps capability. For more information check out [Stream Maps](https://sdk.meltano.com/en/latest/stream_maps.html). | +| stream_map_config | False | None | User-defined config values to be used within map expressions. | +| faker_config | False | None | Config for the [`Faker`](https://faker.readthedocs.io/en/master/) instance variable `fake` used within map expressions. Only applicable if the plugin specifies `faker` as an addtional dependency (through the `singer-sdk` `faker` extra or directly). | +| faker_config.seed | False | None | Value to seed the Faker generator for deterministic output: https://faker.readthedocs.io/en/master/#seeding-the-generator | +| faker_config.locale | False | None | One or more LCID locale strings to produce localized output for: https://faker.readthedocs.io/en/master/#localization | +| flattening_enabled | False | None | 'True' to enable schema flattening and automatically expand nested properties. | +| flattening_max_depth | False | None | The max depth to flatten schemas. | + ## Installation ```bash diff --git a/tap_csv/tap.py b/tap_csv/tap.py index 9ff0dc2..a859be3 100644 --- a/tap_csv/tap.py +++ b/tap_csv/tap.py @@ -20,12 +20,32 @@ class TapCSV(Tap): name = "tap-csv" config_jsonschema = th.PropertiesList( + th.Property( + "files", + th.ArrayType( + th.ObjectType( + th.Property("entity", th.StringType, required=True), + th.Property("path", th.StringType, required=True), + th.Property("keys", th.ArrayType(th.StringType), required=True), + th.Property( + "encoding", th.StringType, required=False, default="utf-8" + ), + th.Property("delimiter", th.StringType, required=False), + th.Property("doublequote", th.BooleanType, required=False), + th.Property("escapechar", th.StringType, required=False), + th.Property("quotechar", th.StringType, required=False), + th.Property("skipinitialspace", th.BooleanType, required=False), + th.Property("strict", th.BooleanType, required=False), + ) + ), + description="An array of csv file stream settings", + ), th.Property( "filesystem", th.StringType, required=False, default="local", - description="The filesystem to use for reading files.", + description="The filesystem to use for reading files", allowed_values=[ "local", "ftp", @@ -35,46 +55,73 @@ class TapCSV(Tap): th.Property( "ftp", th.ObjectType( - th.Property("host", th.StringType, required=True), - th.Property("port", th.IntegerType, default=21), - th.Property("username", th.StringType), - th.Property("password", th.StringType, secret=True), - th.Property("encoding", th.StringType, default="utf-8"), + th.Property( + "host", + th.StringType, + required=True, + description="FTP server host", + ), + th.Property( + "port", + th.IntegerType, + default=21, + description="FTP server port", + ), + th.Property( + "username", + th.StringType, + description="FTP username", + ), + th.Property( + "password", + th.StringType, + secret=True, + description="FTP password", + ), + th.Property( + "encoding", + th.StringType, + default="utf-8", + description="FTP server encoding", + ), ), + description="FTP connection settings", ), th.Property( "github", th.ObjectType( - th.Property("org", th.StringType, required=True), - th.Property("repo", th.StringType, required=True), - th.Property("username", th.StringType, required=False), - th.Property("token", th.StringType, required=False, secret=True), - ), - ), - th.Property( - "files", - th.ArrayType( - th.ObjectType( - th.Property("entity", th.StringType, required=True), - th.Property("path", th.StringType, required=True), - th.Property("keys", th.ArrayType(th.StringType), required=True), - th.Property( - "encoding", th.StringType, required=False, default="utf-8" - ), - th.Property("delimiter", th.StringType, required=False), - th.Property("doublequote", th.BooleanType, required=False), - th.Property("escapechar", th.StringType, required=False), - th.Property("quotechar", th.StringType, required=False), - th.Property("skipinitialspace", th.BooleanType, required=False), - th.Property("strict", th.BooleanType, required=False), - ) + th.Property( + "org", + th.StringType, + required=True, + description="GitHub organization or user where the repository is located", + ), + th.Property( + "repo", + th.StringType, + required=True, + description="GitHub repository", + ), + th.Property( + "username", + th.StringType, + required=False, + description="GitHub username", + ), + th.Property( + "token", + th.StringType, + required=False, + secret=True, + description="GitHub token", + ), ), - description="An array of csv file stream settings.", + description="GitHub connection settings", ), th.Property( "csv_files_definition", th.StringType, - description="A path to the JSON file holding an array of file settings.", + description="A path to the JSON file holding an array of file settings", ), th.Property( "add_metadata_columns", @@ -83,7 +130,7 @@ class TapCSV(Tap): default=False, description=( "When True, add the metadata columns (`_sdc_source_file`, " - "`_sdc_source_file_mtime`, `_sdc_source_lineno`) to output." + "`_sdc_source_file_mtime`, `_sdc_source_lineno`) to output" ), ), ).to_dict() From 4a2f30fbf6955ca097dbbe67a860e6a0c66679ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Wed, 4 Sep 2024 20:53:52 -0600 Subject: [PATCH 03/14] Cache stream schema --- tap_csv/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tap_csv/client.py b/tap_csv/client.py index e155e0e..44282c7 100644 --- a/tap_csv/client.py +++ b/tap_csv/client.py @@ -5,6 +5,7 @@ import csv import os import typing as t +from functools import cached_property import fsspec from singer_sdk import typing as th @@ -129,7 +130,7 @@ def get_rows(self, file_path: str) -> t.Iterable[list]: with self.fs.open(file_path, mode="r", encoding=encoding) as f: yield from csv.reader(f, dialect="tap_dialect") - @property + @cached_property def schema(self) -> dict: """Return dictionary of record schema. From d5037badfb283df0b079dbe406a7d92f5dc95005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Wed, 4 Sep 2024 20:54:39 -0600 Subject: [PATCH 04/14] Make settings `password` for backwards compatibility --- meltano.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meltano.yml b/meltano.yml index 9cb819f..85eac03 100644 --- a/meltano.yml +++ b/meltano.yml @@ -48,7 +48,7 @@ plugins: - name: ftp.password label: FTP Password description: Password for the FTP server - kind: string + kind: password sensitive: true - name: ftp.encoding label: FTP Encoding @@ -71,7 +71,7 @@ plugins: - name: github.token label: GitHub Token description: Token for GitHub - kind: string + kind: password sensitive: true - name: files From c91c3b0ea3d403c1f271727429f512a2216ee00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Wed, 4 Sep 2024 20:56:16 -0600 Subject: [PATCH 05/14] Support for dropbox --- README.md | 36 +++++----- meltano.yml | 7 ++ poetry.lock | 177 ++++++++++++++++++++++++++++++++----------------- pyproject.toml | 6 ++ tap_csv/tap.py | 14 ++++ 5 files changed, 162 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index eff7008..862ecd5 100644 --- a/README.md +++ b/README.md @@ -15,23 +15,25 @@ Note: This tap currently does not support incremental state. ## Settings -| Setting | Required | Default | Description | -| :------------------- | :------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| files | False | None | An array of csv file stream settings | -| filesystem | False | local | The filesystem to use for reading files | -| ftp | False | None | FTP connection settings | -| ftp.host | True | None | FTP server host | -| ftp.port | False | 21 | FTP server port | -| ftp.username | False | None | FTP username | -| ftp.password | False | None | FTP password | -| ftp.encoding | False | utf-8 | FTP server encoding | -| github | False | None | GitHub connection settings | -| github.org | True | None | GitHub organization or user where the repository is located | -| github.repo | True | None | GitHub repository | -| github.username | False | None | GitHub username | -| github.token | False | None | GitHub token | -| csv_files_definition | False | None | A path to the JSON file holding an array of file settings | -| add_metadata_columns | False | 0 | When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output | +| Setting | Required | Default | Description | +| :------------------- | :------- | :------ | :----------------------------------------------------------------------------------------------------------------- | +| files | False | None | An array of csv file stream settings | +| filesystem | False | local | The filesystem to use for reading files | +| ftp | False | None | FTP connection settings | +| ftp.host | True | None | FTP server host | +| ftp.port | False | 21 | FTP server port | +| ftp.username | False | None | FTP username | +| ftp.password | False | None | FTP password | +| ftp.encoding | False | utf-8 | FTP server encoding | +| github | False | None | GitHub connection settings | +| github.org | True | None | GitHub organization or user where the repository is located | +| github.repo | True | None | GitHub repository | +| github.username | False | None | GitHub username | +| github.token | False | None | GitHub token | +| dropbox | False | None | Dropbox connection settings | +| dropbox.token | True | None | Dropbox token | +| csv_files_definition | False | None | A path to the JSON file holding an array of file settings | +| add_metadata_columns | False | 0 | When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output | A full list of supported settings and capabilities is available by running: `tap-csv --about` diff --git a/meltano.yml b/meltano.yml index 85eac03..c18b189 100644 --- a/meltano.yml +++ b/meltano.yml @@ -74,6 +74,13 @@ plugins: kind: password sensitive: true + # Dropbox settings + - name: dropbox.token + label: Dropbox Token + description: Token for Dropbox + kind: password + sensitive: true + - name: files description: Array of objects containing keys - `entity`, `path`, `keys`, `encoding` (Optional), `delimiter` (Optional), `doublequote` (Optional), `escapechar` (Optional), `quotechar` (Optional), `skipinitialspace` (Optional), `strict` (Optional) kind: array diff --git a/poetry.lock b/poetry.lock index eed177d..44acb4e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -83,13 +83,13 @@ files = [ [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -300,6 +300,38 @@ files = [ [package.extras] toml = ["tomli"] +[[package]] +name = "dropbox" +version = "12.0.2" +description = "Official Dropbox API Client" +optional = true +python-versions = "*" +files = [ + {file = "dropbox-12.0.2-py2-none-any.whl", hash = "sha256:4b8207a9f4afd33726ec886c0d223f4bbc42fe649b87718690a24704f5e24c0c"}, + {file = "dropbox-12.0.2-py3-none-any.whl", hash = "sha256:c5b7e9c2668adb6b12dcecd84342565dc50f7d35ab6a748d155cb79040979d1c"}, + {file = "dropbox-12.0.2.tar.gz", hash = "sha256:50057fd5ad5fcf047f542dfc6747a896e7ef982f1b5f8500daf51f3abd609962"}, +] + +[package.dependencies] +requests = ">=2.16.2" +six = ">=1.12.0" +stone = ">=2,<3.3.3" + +[[package]] +name = "dropboxdrivefs" +version = "1.4.1" +description = "Dropbox implementation for fsspec module" +optional = true +python-versions = ">=3.5" +files = [ + {file = "dropboxdrivefs-1.4.1.tar.gz", hash = "sha256:6f3c6061d045813553ce91ed0e2b682f1d70bec74011943c92b3181faacefd34"}, +] + +[package.dependencies] +dropbox = "*" +fsspec = "*" +requests = "*" + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -961,19 +993,23 @@ files = [ [[package]] name = "setuptools" -version = "73.0.1" +version = "74.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-73.0.1-py3-none-any.whl", hash = "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e"}, - {file = "setuptools-73.0.1.tar.gz", hash = "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193"}, + {file = "setuptools-74.1.1-py3-none-any.whl", hash = "sha256:fc91b5f89e392ef5b77fe143b17e32f65d3024744fba66dc3afe07201684d766"}, + {file = "setuptools-74.1.1.tar.gz", hash = "sha256:2353af060c06388be1cecbf5953dcdb1f38362f87a2356c480b6b4d5fcfc8847"}, ] [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.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.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)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +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"] [[package]] name = "simpleeval" @@ -1159,60 +1195,60 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.32" +version = "2.0.34" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-win32.whl", hash = "sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-win32.whl", hash = "sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-win32.whl", hash = "sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-win_amd64.whl", hash = "sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-win32.whl", hash = "sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-win32.whl", hash = "sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-win32.whl", hash = "sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84"}, - {file = "SQLAlchemy-2.0.32-py3-none-any.whl", hash = "sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202"}, - {file = "SQLAlchemy-2.0.32.tar.gz", hash = "sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d0b2cf8791ab5fb9e3aa3d9a79a0d5d51f55b6357eecf532a120ba3b5524db"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:243f92596f4fd4c8bd30ab8e8dd5965afe226363d75cab2468f2c707f64cd83b"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ea54f7300553af0a2a7235e9b85f4204e1fc21848f917a3213b0e0818de9a24"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:173f5f122d2e1bff8fbd9f7811b7942bead1f5e9f371cdf9e670b327e6703ebd"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:196958cde924a00488e3e83ff917be3b73cd4ed8352bbc0f2989333176d1c54d"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd90c221ed4e60ac9d476db967f436cfcecbd4ef744537c0f2d5291439848768"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-win32.whl", hash = "sha256:3166dfff2d16fe9be3241ee60ece6fcb01cf8e74dd7c5e0b64f8e19fab44911b"}, + {file = "SQLAlchemy-2.0.34-cp310-cp310-win_amd64.whl", hash = "sha256:6831a78bbd3c40f909b3e5233f87341f12d0b34a58f14115c9e94b4cdaf726d3"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7db3db284a0edaebe87f8f6642c2b2c27ed85c3e70064b84d1c9e4ec06d5d84"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:430093fce0efc7941d911d34f75a70084f12f6ca5c15d19595c18753edb7c33b"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79cb400c360c7c210097b147c16a9e4c14688a6402445ac848f296ade6283bbc"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1b30f31a36c7f3fee848391ff77eebdd3af5750bf95fbf9b8b5323edfdb4ec"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fddde2368e777ea2a4891a3fb4341e910a056be0bb15303bf1b92f073b80c02"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80bd73ea335203b125cf1d8e50fef06be709619eb6ab9e7b891ea34b5baa2287"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-win32.whl", hash = "sha256:6daeb8382d0df526372abd9cb795c992e18eed25ef2c43afe518c73f8cccb721"}, + {file = "SQLAlchemy-2.0.34-cp311-cp311-win_amd64.whl", hash = "sha256:5bc08e75ed11693ecb648b7a0a4ed80da6d10845e44be0c98c03f2f880b68ff4"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:53e68b091492c8ed2bd0141e00ad3089bcc6bf0e6ec4142ad6505b4afe64163e"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bcd18441a49499bf5528deaa9dee1f5c01ca491fc2791b13604e8f972877f812"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:165bbe0b376541092bf49542bd9827b048357f4623486096fc9aaa6d4e7c59a2"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3330415cd387d2b88600e8e26b510d0370db9b7eaf984354a43e19c40df2e2b"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97b850f73f8abbffb66ccbab6e55a195a0eb655e5dc74624d15cff4bfb35bd74"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee4c6917857fd6121ed84f56d1dc78eb1d0e87f845ab5a568aba73e78adf83"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-win32.whl", hash = "sha256:fbb034f565ecbe6c530dff948239377ba859420d146d5f62f0271407ffb8c580"}, + {file = "SQLAlchemy-2.0.34-cp312-cp312-win_amd64.whl", hash = "sha256:707c8f44931a4facd4149b52b75b80544a8d824162602b8cd2fe788207307f9a"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:24af3dc43568f3780b7e1e57c49b41d98b2d940c1fd2e62d65d3928b6f95f021"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60ed6ef0a35c6b76b7640fe452d0e47acc832ccbb8475de549a5cc5f90c2c06"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:413c85cd0177c23e32dee6898c67a5f49296640041d98fddb2c40888fe4daa2e"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:25691f4adfb9d5e796fd48bf1432272f95f4bbe5f89c475a788f31232ea6afba"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:526ce723265643dbc4c7efb54f56648cc30e7abe20f387d763364b3ce7506c82"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-win32.whl", hash = "sha256:13be2cc683b76977a700948411a94c67ad8faf542fa7da2a4b167f2244781cf3"}, + {file = "SQLAlchemy-2.0.34-cp37-cp37m-win_amd64.whl", hash = "sha256:e54ef33ea80d464c3dcfe881eb00ad5921b60f8115ea1a30d781653edc2fd6a2"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43f28005141165edd11fbbf1541c920bd29e167b8bbc1fb410d4fe2269c1667a"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b68094b165a9e930aedef90725a8fcfafe9ef95370cbb54abc0464062dbf808f"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1e03db964e9d32f112bae36f0cc1dcd1988d096cfd75d6a588a3c3def9ab2b"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:203d46bddeaa7982f9c3cc693e5bc93db476ab5de9d4b4640d5c99ff219bee8c"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ae92bebca3b1e6bd203494e5ef919a60fb6dfe4d9a47ed2453211d3bd451b9f5"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9661268415f450c95f72f0ac1217cc6f10256f860eed85c2ae32e75b60278ad8"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-win32.whl", hash = "sha256:895184dfef8708e15f7516bd930bda7e50ead069280d2ce09ba11781b630a434"}, + {file = "SQLAlchemy-2.0.34-cp38-cp38-win_amd64.whl", hash = "sha256:6e7cde3a2221aa89247944cafb1b26616380e30c63e37ed19ff0bba5e968688d"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dbcdf987f3aceef9763b6d7b1fd3e4ee210ddd26cac421d78b3c206d07b2700b"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ce119fc4ce0d64124d37f66a6f2a584fddc3c5001755f8a49f1ca0a177ef9796"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a17d8fac6df9835d8e2b4c5523666e7051d0897a93756518a1fe101c7f47f2f0"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ebc11c54c6ecdd07bb4efbfa1554538982f5432dfb8456958b6d46b9f834bb7"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e6965346fc1491a566e019a4a1d3dfc081ce7ac1a736536367ca305da6472a8"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:220574e78ad986aea8e81ac68821e47ea9202b7e44f251b7ed8c66d9ae3f4278"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-win32.whl", hash = "sha256:b75b00083e7fe6621ce13cfce9d4469c4774e55e8e9d38c305b37f13cf1e874c"}, + {file = "SQLAlchemy-2.0.34-cp39-cp39-win_amd64.whl", hash = "sha256:c29d03e0adf3cc1a8c3ec62d176824972ae29b67a66cbb18daff3062acc6faa8"}, + {file = "SQLAlchemy-2.0.34-py3-none-any.whl", hash = "sha256:7286c353ee6475613d8beff83167374006c6b3e3f0e6491bfe8ca610eb1dec0f"}, + {file = "sqlalchemy-2.0.34.tar.gz", hash = "sha256:10d8f36990dd929690666679b0f42235c159a7051534adb135728ee52828dd22"}, ] [package.dependencies] @@ -1244,6 +1280,22 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] pymysql = ["pymysql"] sqlcipher = ["sqlcipher3_binary"] +[[package]] +name = "stone" +version = "3.3.1" +description = "Stone is an interface description language (IDL) for APIs." +optional = true +python-versions = "*" +files = [ + {file = "stone-3.3.1-py2-none-any.whl", hash = "sha256:cd2f7f9056fc39b16c8fd46a26971dc5ccd30b5c2c246566cd2c0dd27ff96609"}, + {file = "stone-3.3.1-py3-none-any.whl", hash = "sha256:e15866fad249c11a963cce3bdbed37758f2e88c8ff4898616bc0caeb1e216047"}, + {file = "stone-3.3.1.tar.gz", hash = "sha256:4ef0397512f609757975f7ec09b35639d72ba7e3e17ce4ddf399578346b4cb50"}, +] + +[package.dependencies] +ply = ">=3.4" +six = ">=1.12.0" + [[package]] name = "tomli" version = "2.0.1" @@ -1311,13 +1363,13 @@ tests = ["mypy (==1.10.0)", "packaging", "pylint (==2.17.4)", "pytest (==8.0.0)" [[package]] name = "urllib3" -version = "1.26.19" +version = "1.26.20" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, + {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, + {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, ] [package.extras] @@ -1344,7 +1396,10 @@ enabler = ["pytest-enabler (>=2.2)"] test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] +[extras] +dropbox = ["dropboxdrivefs"] + [metadata] lock-version = "2.0" python-versions = ">=3.8" -content-hash = "7311f7090657b96a77f3f79d5b9f164501ba57722d09232e601560c3fdd7034a" +content-hash = "c218fd70889a2509ee65b9a3a85187112437dda863ae5249d0bbeb4bafc57bd1" diff --git a/pyproject.toml b/pyproject.toml index 7da69e2..a8cde72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,12 @@ fsspec = "~=2024.6.1" singer-sdk = "~=0.40.0" universal-pathlib = "~=0.2.3" +# Extras +dropboxdrivefs = {version = "~=1.4.1", optional = true} + +[tool.poetry.extras] +dropbox = ["dropboxdrivefs"] + [tool.poetry.group.dev.dependencies] coverage = ">=7.2" mypy = ">=1.4" diff --git a/tap_csv/tap.py b/tap_csv/tap.py index a859be3..fe3f499 100644 --- a/tap_csv/tap.py +++ b/tap_csv/tap.py @@ -50,6 +50,7 @@ class TapCSV(Tap): "local", "ftp", "github", + "dropbox", ], ), th.Property( @@ -118,6 +119,19 @@ class TapCSV(Tap): ), description="GitHub connection settings", ), + th.Property( + "dropbox", + th.ObjectType( + th.Property( + "token", + th.StringType, + secret=True, + required=True, + description="Dropbox token", + ), + ), + description="Dropbox connection settings", + ), th.Property( "csv_files_definition", th.StringType, From 062e764d25e52ec07fabd30dc5144aabd71e6ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Wed, 4 Sep 2024 21:03:29 -0600 Subject: [PATCH 06/14] Reorganize readme sections --- README.md | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 862ecd5..e39b597 100644 --- a/README.md +++ b/README.md @@ -19,24 +19,18 @@ Note: This tap currently does not support incremental state. | :------------------- | :------- | :------ | :----------------------------------------------------------------------------------------------------------------- | | files | False | None | An array of csv file stream settings | | filesystem | False | local | The filesystem to use for reading files | -| ftp | False | None | FTP connection settings | -| ftp.host | True | None | FTP server host | -| ftp.port | False | 21 | FTP server port | -| ftp.username | False | None | FTP username | -| ftp.password | False | None | FTP password | -| ftp.encoding | False | utf-8 | FTP server encoding | -| github | False | None | GitHub connection settings | -| github.org | True | None | GitHub organization or user where the repository is located | -| github.repo | True | None | GitHub repository | -| github.username | False | None | GitHub username | -| github.token | False | None | GitHub token | -| dropbox | False | None | Dropbox connection settings | -| dropbox.token | True | None | Dropbox token | | csv_files_definition | False | None | A path to the JSON file holding an array of file settings | | add_metadata_columns | False | 0 | When True, add the metadata columns (`_sdc_source_file`, `_sdc_source_file_mtime`, `_sdc_source_lineno`) to output | A full list of supported settings and capabilities is available by running: `tap-csv --about` +The `filesystem` setting can be used to specify the filesystem to use for reading files. The following filesystems are supported: + +- `local`, the default, for reading files from the local filesystem. +- [`ftp`](#ftp), for reading files from an FTP server. +- [`github`](#github), for reading files from a GitHub repository. +- [`dropbox`](#dropbox), for reading files from a Dropbox account. + The `config.json` contains an array called `files` that consists of dictionary objects detailing each destination table to be passed to Singer. Each of those entries contains: * `entity`: The entity name to be passed to singer (i.e. the table) * `path`: Local path to the file to be ingested. Note that this may be a directory, in which case all files in that directory and any of its subdirectories will be recursively processed @@ -95,6 +89,36 @@ Optionally, the files definition can be provided by an external json file: ] ``` +### Filesystem settings + +#### FTP + +| Setting | Required | Default | Description | +| :----------- | :------- | :------ | :---------------------- | +| ftp | False | None | FTP connection settings | +| ftp.host | True | None | FTP server host | +| ftp.port | False | 21 | FTP server port | +| ftp.username | False | None | FTP username | +| ftp.password | False | None | FTP password | +| ftp.encoding | False | utf-8 | FTP server encoding | + +#### GitHub + +| Setting | Required | Default | Description | +| :-------------- | :------- | :------ | :---------------------------------------------------------- | +| github | False | None | GitHub connection settings | +| github.org | True | None | GitHub organization or user where the repository is located | +| github.repo | True | None | GitHub repository | +| github.username | False | None | GitHub username | +| github.token | False | None | GitHub token | + +#### Dropbox + +| Setting | Required | Default | Description | +| :------------ | :------- | :------ | :-------------------------- | +| dropbox | False | None | Dropbox connection settings | +| dropbox.token | True | None | Dropbox token | + ### Built-in Singer SDK settings The following settings are supported by the Singer SDK and are automatically handled by the tap: From acd973345fa2ce3795d826f6ae5b87280411597f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Wed, 4 Sep 2024 21:13:27 -0600 Subject: [PATCH 07/14] Add more Dropbox info --- README.md | 4 ++++ img/dropbox_scopes.png | Bin 0 -> 166195 bytes 2 files changed, 4 insertions(+) create mode 100644 img/dropbox_scopes.png diff --git a/README.md b/README.md index e39b597..9d598e1 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ Optionally, the files definition can be provided by an external json file: | dropbox | False | None | Dropbox connection settings | | dropbox.token | True | None | Dropbox token | +The token needs the `files.content.read` scope: + +[![Dropbox scopes](img/dropbox_scopes.png)](https://www.dropbox.com/developers/apps) + ### Built-in Singer SDK settings The following settings are supported by the Singer SDK and are automatically handled by the tap: diff --git a/img/dropbox_scopes.png b/img/dropbox_scopes.png new file mode 100644 index 0000000000000000000000000000000000000000..e8f4d864ef856dc71d87197bbd2879d804469f3d GIT binary patch literal 166195 zcmeFZWmp{Dwk_N^AxIzu51JssgFA%a4#6FQba02pBM=;d21w%&g1cLAZCrvwaCaJM zzGA<7pL6#6-JSpUxu>6}yNl|zYSpqa#~gDOA*#wUI9Oy@AP@*gPWH7r2!!4W0-;D_ zq623ntraLhAgmm)q@=2xq$IVfvx6nr)&c~Q4T(?0P>r1-3OKmS3;swXE-wE)L)HN) z`y-{exZr1bS>%rduVk&=-#Vdb5#r;k61$?kZmR;76TK#!&HQfSAwh&@VaW11wC_5Q zX1Dp<#X=*Oi*vJpz{Q-){+y7DAE@V9f_OA?KXP;*@q-Ud^WS6CM&8U}wxSTIq7sUm zmvNznr&Id}^fcZ!_-tYfhc}tOjNM7QyVH(Yb>x}`iA!L1JH4FF$4q;DDxgnIh!pTc z`bJQfwhh~Zx{&%c*6YiCY=(iO9_;SHqr{n{VG|F~u&lNxLD+LeP(XIjW&YP))Mt2L zrl0FRxKUAuicLfL`Cy8VQPj2p9hi@xy(&@H3eb-&YvHlK-!T7wZo(ODpxVw5pYXaRsj} zGw7xeEQ!I6gxPbSMSUg}gw0{YqP>W6(G<=@iR-!6zdkpZ)=s6MKVoqH`sJoBBm@5> zwf7-j(nk32M=hU7JVJ~aaTCU2Yu*j4yF1UfM0i%&Z;z9{RAqLkQpp_@e!8mj>3TI3 zE-Pn8Q5?MSN-^n~5w&yd?sM4(Upibg8lNM=2Ojn6;XBh1Pom2WafGaqbHk{yb&wR6 z9@++o^q`A(3=$1;FGJ~j@Q(=yq~4$(*Vn$GPqVB4_zr9j#%UeU|JHzYun%jNkbTgy z)X$F6dW46XO61ebjKnV?U92?tK8iP7Sds;lh%#+vx}J(Ba`FM`H8l!h0M;-_uoaX< zeKvzEvxFraBZwlw_!+qXME>mk8){Tt6V_=|EOGp4T=zivQYs42*%Bi^u3j6dBa#97 zR2%Cs24x@;2ewh5(;GY>{Qxf6rbIw2gQ%MKOW957tef2eclhNZ1^$W5mQ3RQjSy*ao-}T-+ z{_%7oqW%M!ctnP1MwvBMawxBaP^Ry&sWq?Q(m&}&aoxPfLHgK;K z*ObALKNV|;WaHz*jxtAD10;LAeawB~eO`N#3w-uZQyuy%O@||%qM~@lkz(Ou!7UN~ zfoZfo1gDs|AH|V_qa_(>D4tb5wkHUBpz&IOHe&NN_H%lCK78iSN*xLv-5nn4>gvDL z&(-^LJk`l_USvng8OD&sUA_LoKpHbA$N7vCOr9S(E&&mT$k4~0^%noOF8|yZF(=+E z>nD$3REpt^x0H9u=9ATytC3wy@MD#X9*H&WDg4qK&y*-Y6r2VtG*i+kuaqf;34OGQuY-XWtQS6-IT;ZH{Z1vJi`xbO}dG-AG$xT->~OL zvTEt<)+RO8IvyQ$;!T+F&{dgK@w~$rxBss6-R8S@!Nc*3@5XPa##BcgCuBz%$N2L& zf5?rvPW}cbfT2@9a+=vMzcY(-uJN=1zwNCqEN`@t zsy;6NWinxT*7a*T*`^70)r`|=`E`&eMLDIU+P(VKEd8vSkYR&P!@CA=S2W0@rX;^k zO7jEDmNrEAEdz!=Moha?u-H>2irA-kLXj*vtZQr{wXQvKvmtA5R=JlH-6Gu(BVMgi z{h!v|OJ!fd`(J>wTKRx#>_vu}Q)_Aw}mzsx~+ELb)_tZ8=R+$b+*LAnx z;|jCPZ3QDXbF*FE5gx&KUEMINV3E&iU`Av5+xKV`{~kI{G^?e zmlKWimKn@kp>1TCQ~$zZVrJrHfo_3HhnX3j8D6)aDO&kE-N#M?wcE8$)k5BU*H60R zHM&UG1f3M>*jK)-D6Gm5q!PH(httD*;>P_(*#_p~wF5!ZjCe*j(_`?eRkm*>ZMo3kH2`SnLdsFlJHK5Q*5MKsMD z*xkdN?lj9kRX4VWWQgh57xwfPCR}S4xC_0H=*+9$@QHmCGTW{n)` zOkGyTOL$wL+hu#;IR>Ufj?Xd8 z#s9ZN-v>TCE-Gb_Uza2&wTB_QvB!DuRBZgYZi>8G-IsRLyO$!YXke5$Wx+h5wODP{3a{h~#my7!9jn*AL= zilPAl{XD>1LoIaVER~c%FMwlA5GoQG2n{$w0^XuX8-`Nw%=5GWW7Lj7kM zW#Ie%6%D-a>-_bN@+Am_0sKV(ygk#A|5X~jH67(&$0*XkZy*T`NjW*-Tf^Mh!ouFg z+QC&FJo*bb@xW15*98P3dVc>#l2dpHJ3T+E%pj;>$_d+Ph^nwmMdxr)%z-Z%7LufOio!V~=8E!n&L zvs*w1+3$a0=Vaqx|F3HURfX@*3aWxVEo^mPgYAGZ1KJSf=i(RsNBRHXFaO=*|EQ_+ z-!(b;UjAFv|MAn`t7^JfI7>R%0d2a9{`Y+Sv)%vs<3B43v)_09e+fuVEpSFI7SlfkFk028w3&u$-S0%QL>t$s}j|cnv9n_DgqaV#Z#jQbokB%$w{wcw(qrfwMAMyA7 ze0RzV88r@;?w0Q7?p6oJFc-cGF4l>b;^O`MngU2Al|0i|LRE1jwEz6ENr#+83fiIb z9v%F1!5&oX0NqFb`9k-#ui^rbN=2)L=1Kn0B2W;;B;il@q$(aL`rHImsIsTbC;i8Q zfD>Wy$L^`7t2`h9?PxTNMX3F;AP2~j^v?sZsez2%dNsc9YX0Xz0EP+u&n5nMn1HGH z-(mXS)%3rc?*C?N3KV5OJfC&QOEiLTHXU`5gI7Z6l{J(^+>$*Oyv96NBc?WL=5gNq zN7yxaL%11_RH`Bhe|CG=j`#Gu`{QHfq%I1V0o*irFme?trl(!aUNv~S)Ji(ZcDJls znQz|5CE2DpE#mMS6=Qk;GS>h3L)`n}X+3C~xuo$+g3-HP{5N=a^Z4NIrydl`E@IYr zfrEUr+&H8!vr}h$FXq|zYVHtgE&8|Xoy5k9J0&&tSDRT;FWBmhTfn1qQKHGxRKBO7 zi`NDoeym9tPaPFIUHoy6?cKBk+y1mT~iq1boqp5BpDQkNcPj+MbODVo=6) zky@qZYSnJhr^F$fTqJBfzpT1LV8q?opQT9Ri99p(8IgKQB($z$o^zzoPU&~Gl?U$r z<}M#hg=oNCybk`uO`PHc8WDrCE{L02U*udPj-t4C3M(|P`e5}EOD8Zfl@l1B!xhXQ z5zBg8w*ggotR(EDVM8{9RLV1{BXWCk)ZOo8=$xN3nx6+v$Ym3`3o|msE)(b^)QD@j zi1<^xPXmpffV_`;8OGj;8CMlHbbL|By;hJYkv%2Z9x^>K6KO_hFC`b0D0?3?X@AZ7 zhHMhXS}zMZ8RYBt65IN%F&ac}uY;K7`wz2uKh47)Xb?@%u1AZI@HgK{U5mZ`l3Lom zvg`e=c092G(GMe{=mJH~Rh|>l=j7LL=g8XDcVsC{(P%XOM5vXRW2> z_I%d$ph*mutM+mwEbpkBO6(fCpc*B5ZVlPk^B5h!y~;^LoaTXnYRcx30+wEgo0O8~ zs~2{SBhp(jGC>JqqSvV|LbZb;7jwE%KaNp(7RJX=Y&VB9wklwv{RyKj{&(EIVB;9f zxAVX<-WudvkX=>b@Vn|&@k>s4akiP9{re45S@?5wwuNQ5F$R^7Y_d1htGu_H++&X0 zG35D+!Q|u_|0l%1ga0(}=EzO-p!3^{#k@}n5@{Zbz6|Y2Chs4NaBf{ zDUqJ_vTJ(;9}$Cs71T*u@VJMrFRi5XC)U;%iNu6EMB%Az0TRkp;+^Q;=~#uyqO#Eb zI8F4E$BzcC+snFhI*IgIMEi^|@F-LL44p|3zigh0vLl?^I(4?}JP0T% zKbGJ6Y6b0GUv%zg9aEEeYWV98Bgdw=P7oMqkEaPjGjC&aByn#o%<5&0eU79AZ%@ZY zy*8jJ(}@$Km1D{&lwPN0xW*n9cWye-{{Lr;`UiN4M?E}E29ZcUwXYnBk{mB;zS`bO zb%7}WE6C-SQ}ABDs?dI=2Gj6q!|`G#pT8*L()H%Z|An9M&qan*N3&m^u}XbuV-IbL zc&20ySGNaI15oBCX_}C4jz1rap%EJ-k^JIJt7isP z54`M8sNOK%0$^{Tq`3V$L;-eMzXA2GFf#R#06Djz5p8lPRf*Mefp`bG$Fe`kBaNik z*XRG*u7F_}LUi@~;A<5Zs4&b-w}j0>zS9_){#ZA+yLjT?qD@8!)PE~1D z&;4_ZWI2s_UA9{CbCX}pJ8dj+uf=I}$;`NW$l#S8W63+vCtGK7uZDBwXdC-JAJKS` z#yjs?;d+yHm+E`!2iBi~Iw&Z2Qkql@3F`OWcDF7rw+PXWJS>8aTjQ19yzC~kDIATC zs7MTo_YvZJW+6H#d@`_wz@Quur5&!hb)U672*#s=k`TNkXlgd&mkkPNTu-*CDA6ms zGkeDTf4~#q_8uZiYXPj)*40jl0&3XG%o`u&(#v-Mt)xiM^GE}~CBC|U)R>AR8 zVkScZ3Tz+x{ZE3Rjt|)@O@d)iZ^S2-=*i`F!8>bSkTknUP~C8k(`+P|$KLnlsTu0JIu43u7D2xR~nAOHJmTHu;d0y}bk6Lt=65%JK2V z?e&F9&4Rl(nfGp4Kd_NbhJ+5@N@P;`U1r>zWvC0J%vrT^qI4ea2$Lbrpv%PHOY1 z6nnlbmCvDso(Td@Ao=7A$|8fWnv(nmMnWxe<7 zv;}_;ORmCxl+?^QEBrFO-s@W&Tea26=TjFoX-@=psE?j0e64TnXr1a}G0pO;#pG_q zK6b!2BZ%mX;7;MJ>HH}|58U}g$me`Tfju!8^LH4~ty$-SqS3N$$|;((8_uazl)ff3 z`1MK{yBu@z_|c5<8EUIu)m_gAxj#7hkSOsej8??$fxlHd6@WR37V+(PcZSJMxnKMI zPu36H{ZbYHu6b;=0rl|Hv#Xlu^T&IEBjkD5h7o@UwXfeA9ad*AfDp7*UC6i7O0Rh7 zoW9&)x#wA1!;*MRD!kXb6?qK@bu~90jmrX-6?dl$M^@+Zczlrh7y$d+$CUW;;KVxA z`YJcw6~mjXi7HK;pz{LbJHfr`*?qXJYwX!g1Sx$J&QFt_bOlu zTiXT2FZ>NuK)WN|lqzG2TuNS)3zZ6>-8c;ug`JWXzu?9bnF3^!qF?@WZ-?>zAi1Q= zph37n=gYxVxoE^mV!qdVHA*z8jz2@dt4h4R>#U-%5WFnZ(d zX9tU7IL$lz$BR)SSJrv}5$X4j;_M>XY73@R7Vc&lMFGHqch2#{C71W!5Tyw!!^StO zecYXflc6?nYpRR;W#NJtFDu%MU~Kpi-1>U2#s8Q89g5&Ub6+2Gjuq4^_eR&_0%S9R zV78k6ql3VV3QTeJzMxHBhGcL84ey+Fmg}e-L*gAb!dZ4Ugqr zv>n4e!6D(GPVvb2M5KJsa$y7k2>j?1ZKD{!OT;xU3@-RDGa$^~R1Y``i?%cO9Pw&4 zf-e_v!%A*M9F&D_Pb>H9cjCpaw+l+{eGX{z?Rv_wRTz7-=hZyEOl}B$D#t%qePP9r zVtX(iyFV-iKwDqqUqiZuOiI;-6o$YErsmC4suF3*vr zWBfci@WH`P-3JgpOMw`p(m6)za3d2=!=p0*%9$`)lc1nMfJ-nb^Zr}}ygK7x5Q#)V zyp|qk6JT!X6!o`01fpQ%+7vh0e=M2Q@vS-qyik{qFdN_DZ%7=I`q-*OC+hjc+D^%r z4K?WZ7Qsx&SMxv02I7HG;>|M9G~lOxi4?f%-mr}jIiH^4YM^I1^ZXHCy#Oh2-FWH| z$MDrZ5N%Y6@0P!DN!JRh3-Oye5IQw@p_1wy3qbJEtV7GU>N&HM(>WK|S}xg<9e_TB zs4eGn<`<`c^B2J{x&QdRF~c_>`DDNicS%EB>;dy6y~^xP^Z1DCPaB&wkn&+bQSA!WR-IKE ztHT-Kb|kVj?H(U5PAp)*z%lkbl)!MmyrRn4Fdux`U$_RNgluN0mu^RjFPLwijMXgqr4*g? zF&8VAw1^6GexwEuly%8h3<}!(vTxWMOVGEAmnOHXTq#^@G4|e@aBW4x$Yx0Mq`ln` zyJPZi-pmZ6f3Kv#-lPcj>}(pF&^CajDH5Apj zFrUCPWu_Yrnp2tqzk9soG`!4jOi=@}K2dw*HmD6zY&!h;aOPC(t6enW+ z#{~^*ocZu<$~doP0mAHiHlYm$^f?s`6%n_l3c+vxK1r>zk2a4$)BcE)w2r85*{ld& zJu-*JqpP>W@9lg}M`S9fdKFm8UfVj?H2VS6X=}mzK#HOX)ySw!>dGB{{^#KAfyg zr=#FGr|!K~{aKL|kABvgY=E}#7d7nHgPY;&JJ9&r@dPZwk{q2&K$nH0adZRrGNHJD zfrw~>cgQ34LJ{byxVS$cjDZpG4F@mB?c5amzTzGK%jIBacfcI%+zX)zcjtc-F~tF( z@dWJx_n`y;!6_!z>94NH>*^-Alq+lli(S2K&5^L zP;LI5m|6gIbMM6qpfT?d@;OY=l)o`vNU(UxgMi!9Jh8zbeOmsGZv%H1{&$HyW zj@+jnbDZ~vvPrV&VO=f2K1PAjkKqN#;A@APePwJES&mHxF}U2y&{p#os6PUJy7U1r z*Z5|I_z7P=1G0(7yqk7r_k17VhH$DB-Efeh>>*9cYbI(&fsowxv+rhLep;~KbiT>= zJXZu@(%^O+z5)A8k}c9r6lQMFq@NHcvWXLGCy@`}#BJ@>ECTfD&d+@nCrycKkQ@8~ zhqtG=;IhF`J@sT4X_C#m@CCGaw$LCXWuA^yx}V?<_d>E)1$uwBwz z1HH~E>mn;q=(i#*BKZ-s7QJmq1XH!qJg6HxRfdCX{r4=3y{S5b=GCXKdcW?N@Kg7yf2Xfexc$(<|5{%XsdT|$sNPJ?Zn1LZ#Ihf4azOu}j_z2`)mjr&SUaa< z+{o)Pz-!YkNG>A7slv6BmB_d8Q@TV(@Pt-uLcIv2GjK9vm6j96R?q0vd{3#yaD{ds z8Bh4Ek$u?9cPqBGH13k$`N}us)z9AIqX$R~W|O(+cwAEzL&x&66W2gFE^4$-ZrFx<$g(S7gl9b)z;SXB`Y_K3_0R+c zP^JFf+q0BpS#Y1VoB1|!!x3TCHGHxQ>iKTPD}*}4T)1mA)u7zjcsG8a{* zp6RD2(u^tt;TxrU_O2L!=^d_GbMJn4GQd_m@IGBue3v%%shx-a~!ti{1*(7tbTP!nfw->hj|- z-y6FO^30UgOlaxHGk|k<%S)!|`!)iQQ2P4&T4)x9yUhVhv#Tn~c;V0tx6Ir??d}C& zKK1EETt3A6J8ylO0Pg`XZLdpk`#`XlUI1iO2%7zTz%W2oM(P|}|2^p#zQ*4KXn_^0 z@vCvGmXo?xgF!om44yJyv!UKVM4^1u{QU#^O;xSwZn$|_jI-8&$Ia90cSoJXCBJ6F zSAqE%>W?Ijblaw?Cf@)owOGN9xz~~2fq?njxVs(=Pr%=Fnc?hQ+$D}o$w|LpaHw7SWdf*NgUw-g+pJNXzEx8Y zWRrpZW>J8Ml%G85#)hGX5uObKZer>L69tNJ*4dbf*x>fh6_?jrp9XmzZus|s*5Yk~ z1vXN-yd&1SY~mgd5gQn*);Ni-P$&dMoV;A~1svfh-M$j1p{#vNBWO#9KzMz!3mcNi z_ABU9eO8_?#*;FwX*NHA*|Pg6rOx2|t*xq!NZ&T*sTiH&o6Gc(D>2Ir3NF{pVOwtj z41AL{gTW(M6}>&Y<7^X%hNT#uEVWk=OtGhS=RZDX+NLbd5Ne?R3}IKMI}v%%rTT>Bcbt}Yu`=gRr%HrXm?KlP49unKjBLv~%XeyeRD6aw zd#lK&uEyJvR4JKY2Ifvri9&9N&iK}#HnFw5;RhbGb~Vlm@WPmv#Qlewe?#&rY4- z^rHZ(MQ-SDdg~20+Ylh}>85|8s^cym4iJB|wi+ci;J?fl{buv{Bp%BcEl=rMXW>ROKj{*pmp! z2XxM#XdA@XiP77lM2_&kM!}J6jlqP(Fx)VCbE9`6RFIvmx!AUF)NE` zuLr|r5jtk_U#T| zWECJ-`Q|2H(rD1iAC;@`ER;0;t4wWHo$e?T{XKU{?@ z>jQJ0J5yN_Q0KBp401y5MxE2K%IPSBAr{P|Lys$H;6J(4L>7xI*dJc6!;B2P!n*b!Sb@_RR9MV#-s*HPE|6?au>O25nH z!d;G!WNwy-TAD*esBA<+#Y+8(LnL1+XR&**Z=4!g{sWyaW(_rf6aU(gFO5vVs-wK2 z;znj6Gu&L>SH&?F5_*-|fnXJNiEw$~Mq&|V0_x`4;I+r4{{AYHZFxGocp&edObb;% z2r3s{&lw7VGb(T&Pm+VeP82;-xybXQ%*nH`xgn8e2+PTCoR<{l1~QJyD?SRhPdCW= zI4lUQ`ZTho`^*P4_No>@BquT=JvdM2unC!ln1SHBE^WHJN!ZI?vB-lPj&W4HY0IG^ z_zqnk3oh#3gO6((agXg)S15iS=PU3BtJ>#}@$|^-Xn->&Kzl$C(KZ?HsZ2_pJkA8*NK)b+PDP<=D$adA=MeXnvZ`9pd`H*vQ!L z?y;;{O6IO(7}wlQb7UfN_*}bILo$2omrSSfU!rp%T{x znY1|iXsjQvML4U#8F=*8%fH^J{B2jS{k5x={B9nn_u_fTn9l>47t1sE_%H*XU7g!t zv`1wr0DVRFhB1$mgX~AGHxxb9CzNW-N4ou|ve4d}{k>MaxBGr;!R-CZ-us9M^tWV6 z)&?uV>=B<&!+Y}NkxH$@Um*CcME%~5fgbfUaGd3d-7?t>+=oFcrf!bGk21BJES#8d;xqyLFEW!(wiMEU~s321Ar*_%|F%cuBGLpK@*ySweXp1h5 z8{}8XtPN`D04t^YE}lhje+a}KRE6NHNDtm zdK6;52`H#TeXMJt$C@f;X%z^GhKJ$=T?P!5jyrz~M z3I=ZYO!?CD6Q_meJY*nqs8$+RN`6!pc66HbkecG+=2a5ZM6B(jS=0+;9#3c1pGTw{ z)RSY@UT>j#`7t1!-(gF#i1lRt64maJOPEtZjzdOWq&|4nL<`{=d{!~I0!;D;ZHc(knK}N{0iS8+IBPG*Z%FT>9QwJ8etP& zJU(HF6R_Ob+!=ZMBxENRV6WT_#a4HZhoe3kR!r%rxra_o9|`O%Nh2d0E{EYwy*40! zg5ss9;yd{0bG$uh<=V2J;w1U+ei!p_0g4ItjWOUW&U`CIY)18(9&j|csp+37oX6x4L~q7 zVm>43hxL2E$3Zo<-pxk(UO_mkjvX-a=oL)RZ}$Y`Kz16&1WA5^LJzF_Z{^q@bQHP! z4#U~Vc#k8h@2Txqcne@UoIE&@8hzU7`a^}aW`l07jt{b8%5;kBNBLuo{f>NvT|%ho zaOz?*mvd_!e)v*0k^P7V0=}4xV zh+b`2N<*E^bL1jaMP{@dOl~|fZbqBe&(kHgbAn4@p^Nt#GruWT2EXNBy0(7>3t=Oo^AN8(|A*b>?D=>DmK8$jC zfaC|^Abc!2rDiq1Ma!bu3I%c=WmBG2Xq%BA9%qSpX>!=>o4G)LU>+PmkF1=Zlk zt$lblBpZ0^IaZ8;x$+@4kE$DfajTt&TCf0%nLe<>tVB~3FVW0I^th`E>r68z<6@Ju z?@as1VAR&H7f(`y>y!nFp!i}Fzw5XMLn2u#730Umof92Fn}4x+W+a_)JV8_WmTqDT zP5P*-&t!akJ&+Lb?pmx^D2(scb&ZUf zBxHCeZ~-p{Sg=cKh)DP)bjmt=neCVH-PIJlr2JyUvx|ybo{0Q;EnVso!R&F$;!Un( zv-vF?L;{moV$&eoxg0Srph>nEV-BVUNk~AWVm+8Fd8>0sK<&8gH>zBnUJrbRK?b|M zz*A(M3n*~-j568XG(r|wxdR$oRRDHyipLpKdS&~R;q54Ke;lFKvL)G z$>9!?7Caf?ssQPhQ)V* zO{A;*tmrByCoemmH-&G5IV_s3Q;Uf}Hr1(XCvpBN?9cbh^J*}0qT%&y$O3a92~}ow zTMtgqB%OoXv@FpgRbf*q_5kT=e@K1WavkQhOsKdVA}RD>C4LE0;)~u` zM`dGIef?_cS7VhU->NJAKJl!L?<>b){@QxRam5-Gu#?ZeZUi@zyXEUv3v4mrW)b5&h*wtKTf_61HRH?i#xjgc!U z*3>rSX_zdi8ko*QUFSGpamy**e+MemqBIvH_O|bGnp9-J*0HPt=@dbI)Dj&Z%Qedw z0@{amzk${D(BD@g+2c(fq*AkLu&nvzW9YSpPbBKt%ioUzqi;$b;T9by&ubqiqi4vD zSnD*Va5Zo6kby}uKM6&Ig=B2$D3={Eial+wJ_^S|7Kdken%ytDSqb)J)Ak?>94XXP z>+vF@^ek;`oGEOz*X&&Thj~X0>Ic!&2>@!mf7%H$^&`*BQ*!#=X8q{<#IUsLN27-= zw|fr#5ylbrR-)|iiwM-#P!If#L=C1W_<@%)0Zb<|=K9E#sx)9&>RfnNJ zCnM$TDC!I!o1RKoKe%gCb|n3t6=Zzqq4S6tqx-JD0(aY;^+C}<%{#_XynV`O@SAaoi%vLiZedhS%woc{65@?`vy!%?sHs}cT%E<=dCR`S3Nbd{N%}a7Wk~2N^bW&Q)FXwD zdv?1rZw8rSYF6qvS{61r2dXqqqYvc$%x6$nVEn7$$6Ohn3#;!6iinK)PJhYXQZ;?v zeo!qHRjk+6?<3uyuH6l<*J0>9UL~vJcQx6))0;wf@>TO$x6&>y%iMkQFyM(p=I6a7 z9(w|&bNB4XVqR1;<~{>ayk_lx14P2j>w)wmla*_d z60tj9goua+Nj1GXH`zK0*O6gkSCs3qhL1hbSVxrie!zP1jr={&8BhU*Q*F-)i{zcdU_;1Z+Uy{|! zag(W4V*=)1-iwj@EXedQ_et39ih$i4=?ec za<7IznQrvhoK}aos$%;~9lYK*C}HU2(mZa8H@nO;JIrIYr~&MZnWT=$Y&W;z49qKW zs8g<@%3HkSaoYcz}UH)cE#D-|?mdtS$-ZP4gE*}wHJ3Y|@dBgb$kWLlkz0cWeP$3Bk z9aT*7gMg|Z15%Vee+$>1cvg}R_{+{$(^zi@MR>S zhlmFc$Q_6cS&5JxO9bl3G;rncNoP?y^M6;5xqJpz{8>rj}oj3$6vM-#LYb#rW?}+00f@4P9;z&U?t-SUPq~aN+?N zL>5pNCN}o1ZliSAt+9>q=_im5fIGVk_uq9qbpc(_e`BnD{lnJ9uC)I-B{+aP~+s z)(rHF3?&RFenK?LNCQalww#pAQ1{E^Q*FNCFyxlyRHT&Dc9L;Dni1r7AMyT#u0Ynk znIY>~f9caGzY_sl@iInr+!_Ruvb(LCB>YMmG{{-bNF|vRymKJIlgZ3C`*83J&lDG7)G?A||^hfHk1c zjMkcLNYxZy4CIpU&g4)8V+YHsxI-96V{6pkRSRqB5v6t39=K^$7bn{0DqF!(4z1F#M8on4G zcL)S75sPG#2F2H>p7>V1B%O`%x2r}(T~+^rzi5f9W!tlD=@2%|FW6#=#DG~BoDTeA zG|vL4Qh^2Ac}&UQaubU1t!F_x*duQaDs0{t0FQ|L{%ZAMWXTxDMeS)s*#7Hx8j@NO zX9!IP=9^)02}%DP>H5vDsub^wXSzD4G2)HLXO!Rj0@=o{?lQhr)Cv_|;X)~4uqU*z z!o&k+oWSYL`6<&!B44zOyw)l^2!MZcvIY?O?ROv+GV~LeG*iiMe}@(OlNGM46?=QA zQg^8e>RM>TQO&%&K5r_eNHodS5B^FmC&PF|5eL>0`)bRTeH^a-DdEr1Z6IaR$3FwX`gCCjN`hGO`F zavAhp$zVeFyZ!D#2ciQr#-`QMD3dZ$*{RJe9A3P)TlLNwXV6*9J zv&@Y5U0-}8<*XutSm?;Wp&r!T$E(V-T4$hDWxahucKS(4ab{?n6bcVcZnk{W!b%+_ zoaV8OodS2?0MC>`NJH1j7J&RcKBS1~2A`Qp*+E`5-tuo{#qUZuS#+w5um{&UAvE~m zw2bj8K=!uG&!jiINL|eN6-x92d9dB^R6N3`l6k~?mm+ffKo>= z1UwF~Tf8@+Z7ed9l>S&KS(SPDsA8<>X#f%-~HYL*4-_!(9$ zjDeKeg+y9w!y128XaV9FzAR02xBL1BQ3@+;JehW){CEIA_N|UJn3mePz?&0YN4@92 z`wb~j2KpVL+>9Fb6{Ykr_nF z&K+XW_7+ywClEqI$UOf{(zhQG4xN+?!tM;NfJFhCSq=>I*1FK`m8(hh`;PWFrRM@Z1C{pcLd z_vlz;4>7BUvp!1i-aM@b62+xI;Nd(KzP12jsxUGf>(UhrZk$(eQ!H@6`d9AL(&ZtI z+`NpytxcgiT;G5FF90TKNmLveo#@QA5NTzoVVnxKZnxnt9ZrMCLENc_H^{rz)EUc- zBrIUS{t z0h?3~s)K&bu=w3@j_5t>oRab??lmLX=@C$QV@#g8D2|8QjR({P0Vicjd_$M-!?;fI zRZI^#mNX}gID|`g_c)-YUU~!JP#9#n!=q6h-HVr`DMXgrRtsy}(s=TcJ;*d0Dek2* zif_)i?acEuZtKypurA}q86#wKR5I(*RjS1rAm3%;R?z{y4MFhoCYpa(61YyikrJ7Wch)j6 zMjSAbQ)r`Jd1@InFZ1L^?B!BEqfSu)e7>X>p??2Uj*Piw*~3KfMc|>ouOfJlv?1>+ zUx2#KUw`1}2CaQ?D|Zk;_guh-FZqm)0bseas%H_f$DoN7z|$ZKNJ$1P??pR1%B1F% zSA~Y)1uN3l#b8@;tAvRqw;_BW`21JFsNCnx|fTbsm) z?RqA@e2~`-_MlM3Je^_o>)2NEW?+tB6$1KRVutGaSe@Wmd16|{v;KR_@BmzB z4$EJGSdOpce=tllJAtw)bh}NgnQG0z*dZ!E*iV`|@)EJA=1$k;WE`Rb>rS38{l zp)jo1$*F)hQTuJ(Q)hZRscf!F?U!&tm61gUHF^c?@_}e4FPGmrv8tCE#C%RBd9u3H zBr-N^h0cMYhjLu*zhhK;Uqx=k3fMa3)a(KFnNgCDHq;c8bP809Kyu3?k&nH`yVNv4 zXR$I3Jg0TvgAbXUQGP^}6{Iy)A&NPggVlXv5nNG13%`GG(FQny1WXE~*4 zF~_-nzT9E#9|`#K4_(5pP-!z_Dzab75KfwQ#pTza(Lwf}iv(*vs$H2p_DCcpuTbe; z8zu581mmXGtiHF;n#$bTKH7ekL?cC6UJSM<`4An>?|(@rgz^j=n$|=0dp|U6b7{Kk z6G-Z^*HaIwAskv4=XWQCD(wU3(bf_s;>z7p)b$3?!6zstNp7h4k>J|={`CA>lN27I zsTlc~1=EnoGVO6xhzn)sAbf*^;ZfO~(~@FsUKRcI_}olX^cfd#?Y zhu!CZ>lc0tLzO)?GnknOoAeP#1xD{sSYBlm5;6}`i=$nW-zVOEg~4zC(2SL_-(>igFgCM%?^7m6U~RI=PXVHV zHYZ}4z^i-&z+XgDDKOpmZ1ouhl zx=s4u*UyT>Z3{o`KkJe47B2%nQYr(8OFU}(VN)zc_B`z}Q-9=JXWzaCbO>6d{CUX& zAnx&dyqdGR4{&Ap&M_`9|GaF_?-cQ0A;W9Su!|MoVm6(UOEve3|Ch8UN9+L6O92Ko`;qa6pNy;Nw~4+ZHu3rE$See6YtM3CcJfGt(O!|Gaj8uv z%sK?YaLn43=GF0}u`@-O2%kx(0bAjcg<8c-ad;l2hNxd&=V~Whk%tiLrV-vAmj@gl zN)-8g=LURnnB)5B0sS4SAq_jWipGc!*>z0&EpzDlO{@UWqgfF z!c?|e6RQ$rN#~=X>CzvXqjZ?cfVc00+gxi0kbAKme3w@x^%{STH@F0Z8JUR7f~^#J zyorMw?lX7kUg>Rk22@1a%s@k;>yoDshWq%qPQHDS+@x~`x-$aVJRf!OOw7sEjMW{vYst?+_FKZC z38^wwH6;47WkpBB9CQ2j&Y*wA_hPN6mnATIt?TK=i1@p7IKAYP@BvwL`Cg^?FlBQE z8ZhOnpiC85L;=FTp@?1x5N~qbwD48mOFg46lhSors);{|UyGFC!@POjxMctT0ty6X z;Q>-+*Xv4sSVR}NwWBT+$s1Ene_6*=~mk1OOMzWm129%SkxD)Tz7ua4J@4XX2Hl|5lvw48>yL83$ z6F!mnUm#~toHO#a-vB96dsUtbQD@CcnPhVTCgdVa-eorLaqa7Fy1Q&Z1pZ~Pb>UwR z;zg341IWY4`aEXQBKF~cbLc@L;^PTuw7yR%agHVIK1y%a>~+HRhGHrT5!$bUAY*nU z&bg4`bjOZV9evA0F2D=S#ZflRkRt{U_hM}MGjae(QWY=nNB{w3oj|0QeOCZ1ng4U$ z10dI}waUFZm}9MI*)PRJ5iI%lL4DDH|IPqD&CYU$;(sjvzkke02881Wg@OZi|M6b> z4{tRWEkF(8=Y?qetIF^nT}u4jLO{XkwHL+y@jut*-~ZhhKn}7UA8Y>4-~abx^eO?q zfl-V3Xwv`t+x<70zL+cUN7GzgS^gbF{`-511sX8`-yr#zsIKsTQpo@ReAxj1#^GL3 zwgb!H`2YMha>OtJe+0MFgTjBT!@qybc|-twN`L&ccJ%)J5C8F)bKU~SsiD`1Bl>@S zux{u?FlFgr)c>eP{l{}&6bC#Ff`>F0#sA}@Q2PZu|CW*rwg3HSF9+j)SMA@I$p7xO z|9-6g_k{lYF8SZf<6l?!|6U&ddwKjjy88cid0bk<9BwBYt40f*OWmFJMo-Tf`)hjq zJVX{zDz==0duw91d~eszt7}<3))`(;WzS2@NvCg=2+1Abafpo(KIel zMuhN&eyURHe|qKbf?iC$hM?`p7q8PBdbnv7LAOPV_y!qpi^2E*Iad6~0(&^hiCoCq z`S7{G?h!C|#{(w1k=R-m-Ms(#R*^Du<%HiVpuW;+b?ST7k4t(2vc3bHh@M6 zL2bzwdN?qCR(P=jroDI+TMjA(dj!0fkXKCAY~Hkb3r`4LD0u;YcN!3LCsz2q6icr` zfB}cWa&UqH<;#soX*HM(x(iqyQ~{Nz0anpbK5ko9_+NW-Gal z^ILrYB>XMjZY;)uMvNxyYqlO^bjdXU6M^N0iUV-6)|3GAg^D|7Ps2V?eM%YtTD@9( zADH|;Dsc=`+W5D5&}41KS-nT-zspjOPE zj~W{I1@FfIK#Tt6&)eGcT_P@RWmiWSO1yQGD{Z9+4F*Fzd zY_Q)UU65@5tWXT%xG{O0{Hy^mYsW3+3V=vk5PIGQsuHLY%YUg?NZVBiqP6HDE zKkKcP0A}mc?;LTP(vqJFt%;S=UalnigHj&)VMjn?J_Yc6Hy)~zV80k1rQTLgh}=_? zpetpfN0it82C208qmg9$J>RccF$$b^!Pi|#-c-$UU)FcMn5~K#f7k%NH&r|pKGSQ* zP~uN=@ya~<&T);8_duOb3BY9;f3S#^o&r?5tBp&h1Fv^W1FrmZ5i>hq!-+neN|v>u7Bk8Ix1!?GFy*2WX9BQJj7Q2;a@8{oGcrFB}|h=HdOJqM$Av(U1|0H}onP#SJdZ%a9YY2@DlUK`VEAJD{Cj)|B34l zfd2!Y0+TY=q?9sKjpKL_GRv&rub1cX=F7c=q_x$39WUQaqmUEwBcMQ^wrPAZr~L!C z10*&c0``vCT{1(f9bsO&Pj@cuQ-u4EtJ)t%l{w+g?i14McF(v06K%ny%p2zWvF=Es z*~;Y2UteLX?`H2m`vUclCyu`f%(x~gfb`jj{-8oyt)%R`OwzQ9F!z`ynv&b#ioPO- zfe&A%^8mxbZ{Y^n>9`pVY|*xHFV^mRUJ}UqC0P*t(VxBvh?6Z4nol zVPvX2pI$v|jF0&IAd?1A6namaEvtk7Z7mIpx!;?4Rsmd?4l~wHlDbF@W9QA)7ZtkH zgp${!jsjH~lh%iup{MedHxdU6*;GsQZ~qX&vW1GTewkJt(ckglTRUrl3C-U?LcxV) zb7-M(TCN-hYF5Y1u>erTsH)z(UG!Wr#P$#?uxa7jU){ny9>S-7{sp7QeEy== z23*sMB~{2>pNZ>7JcJyN0IxM2rpKdsb*tgINbUKs>*P3~4!7H#1Jok1iOH+gS?-P~ zZvH&FKPX`a*h&DCu66&{-_`?l`cHssj24W_J6hj+p~K*yv?mE~GHdbBM)!N}Akn?* zCj5S+b4l|rU`HQ!Xq*R(7ccM44>vL|IW$9hHS3%eQrA8cItEA<9@nFQ=MKh`1qmca zZpaOM{*9JDw=dM835D+D5`AM@50x69P`33bMlzUr>!*FN8ZF+LiPG^y8h{k6MNXbe z^9jD18yUcXfD9{kVRdW`6FY3FtF)3vnA)`(4O!c6H46J9PxUcg@#*iuZd@IoydvPh z6*b}Oty0+bUbHDXsy{qsN(Jpa>EE4?u)aYHP|p&5-nh_!*3WgxEjLuY)EVf|e|sk* zm22zh)4a(levn?roM_FN3^R>z2VCeqzpfskK>gHG5^)Z#e)dl97LHedY43(K=XR1H8QiO2b^o_%qnp7B|ttz4z?ycL3id_xwjPKM~yCw{=t zZNT&1Ul-2AVB%PVBuD^v&S8tykzmd3`UkJ%1K`aTN-z)Avib6?GlG4OwDhSlcaek9 zcifTSe1e;9$&isff^TB#sN86XHTWp!K~qQIqn}^L!~OGp=krJ?(@A-hNt1JyypHYK zET^*H%2~&%%PV1P(32@(@+GAriUJ&)+`kyl^#LWZuYt{zLiX%O+MPEN*dn)ov6jR# zhuHDl^-4&SduKiIf@l!M zvaNLj9(twYtxDV#WZszClJO|LVo>HcUX||pIYakAe{HCo@EjU(bGWIhXitRTE6B)L zQLam8JcE5%SvALVzMQBFmYiAd_u?}?fn+~^Q%}gPEN|s=Y==M|e1x}?CL|sC2HsRG zT|lF6)UWA-$Bf|TG_!fVBFKTud7-8T2)-=slVjJ$jQ}&inG!qri-!<=G6$H)HZ}R6OlCs(mdj;q($4qKkbuCF)yfs1C1j}8G7^G$0%$38!neNGe+siFZePjN zgC^RqRSbS>w{{hEKL??+%1MS{DMu$|6?P-O{|;}HsI9B)e>Z(bh46;RJ<7^~t#J>1 zLNwcu+S!>62zLtLv4rR<0C447mwO+Zw0Knk`W2Uvv4wsFbJZuPh9U_)srv87 zAU8S#S{;RZawoB{ADb@(%@<&19vr3fUkKyO=JNxj{v2GkrK>%6fB$?ItwA+Bz6Y3% zY+8=*I=`e8Ewt56fVwsegOO<|{~khy6=5snI`6Kkrr)PO@IAoOeg~YdyoN4k{R@T@ z>~DLe>~*}v9r;twF{%&)j{9s2vQ zqZ{Uo7?t%t8+h-o=ju1-lmoN`{(sH6Oi=vE_VqA$hQz+=L1CP9t=sD6#P#9DWgcP+#G;LfkQ9ybE&dZb|wlh4uO)pmcWT) z9Ok_T;Lk32F<6g?PP?qsS=h)yfWy|b??w^ne%ZMGpcIVuJrq-D&-db2=OZ(^l-8R+ zROz{3f1;S87jVY{G|iUan)CXw_k(CX9U+E2RD3Tj=utc$c>?s&rZ91;tg0hz+jg8E zqV%Fm3~QJk2}ha)Pztnfg2`$9*wz*OQvx9hN|#1f7GT#p6o8W?!E8?Y z3(`&mV;&U3hS{dP=*xMloG~RgkjBj!shM{;HY!9$(2wxN`(*hBOw95UEh8tN z|4?uo6675MaxK3FFFqsy@l|quLhz?IhO35|R5n4sF*uhipNSpwU?bJlj<7op@We9T zzwN0}%CkE?qd!yF{(JmdRAsUBJa zKOeSEzIH~!5_!D&!11}=u~Fp#fD>jjUnh4ySn7n{wkr}_`Ku=t`_Jn_y*g8{$Key` zqh{wPlzQ6|AOJP3icj&H7lO1u31p}ug6|oX`y3O2)5N-D48)MCJn~fcbyFNA=KKzy zfCf-GX3i9s55d9C?YnOiP#O)+!B-asp6g#z4}ehlZ8*vL)k|M0YGPaA2nNa%z!z4- z3NTpe4wna^p|$-Uq`b%pesvy6B&Y#3OxJi<ONaHLl8>Y?(BV#bG!Wkia9jCTV1xHiDVFik6rvU06+7?;f`;x{V6gGSVX zPrUYBypFUL5vur*Qj-1GhZ-;-I-zY$f7;8VUD>BKlgxb$>YOn&t00Y^41C5MZ7m5Xc3okim2^%Uh~%=(mYIvZ%oP z6_Yc&Q2wN~;*X=r{%^Ug)f$BX=fX;AcIXY?WNRW%H?X@pdgmg^Hb<8~?q3&2)888u zxkNZItE@<@bX^g$%-WefjaOd4l~0;y2st11aog5^bit4@#B;+Qp=E`xy{{R+wO6-A zk&5ydCmvPZxIyd8FW$TuG-9gzV{6dr%-nnRrn9c8o68Tm+Rjh+JiSWqxo(;7#z|PI zxxnEsiReDkxbTC@#xJ!elKhk+nJWIYk_i$+S@vkEdq;Q^?LPY3aMng^cig{yO6D+# zi9JM!H`TpZs)E|qQX7A%1G>J4^aT!xO9tZ-9%c|dozJ}yC{Lw;B_@gKL&TqsHg0+6 z3oT4mq}}wu?Pds4k2M15U-j1?Y%N6(&7o_)H@lwM!A=QCQT^Y9iy6IBY-*_ep-Fn(|y}d{BoP=%REm^$og;xB;Uj)T4it> zPpHBD2IDqRSrR^y7@$7*CL!-^FUH8gC&~880(cp}93wq}30H^hw15E_5~_KY$_Aq5 zfPq1uU`&u@TA9M!_hqGiYy%SHR04EAlk?s0BDNA@MJ8pB78fR zoTNqW!D*Bh?px+c1CgkP%_)T{mzPYcnX!}axVw6XCl=bQTF?Z`!XH85tcDn3thPL3=>)Bx#I%Ng|ld4SxcCM^<>`;dV26 z1almr)P}3Q=~D2kkGhO?@uu*SV%~D)hn9uv6cT2_1mP&`sE;HNJ?xHHYy9t4YBLPz zN~+aS0c7`IA0<-@3~KDDlfLo~nu&Z>%)jUBjQ9WmdT8V3{sD#HfmGirLrq$XFXnYf ztQfe{)E(x-W?oM^f!iJ&@(g0;!xH@nWgHhiv=b~?6=k}Aa5umypyI9-ts_Qz?&nyj z+<>x+(!0Iy=GYgF3YQxrlXb4_Em`~>T)qhasfMH8z(r45k3pQV@<-LJ&b^tv)}2N- zjf76vjoF=jCga=ce1OHm7E(>)Dv(;p)fbvDq@@m!_2!iLC?cPFUZovo)V z1NAkTrV`2>+Tw9&u>B8c37#IAWvZ7ouz5$Bs3y)7@);m9``j2QNp7wgr^Ifo5bJA6 zk^Yuuo}6Ej^+kPL8C6XKc`62Vmmk}+`k(<6mHMo1Y|nfizda{FiCRZZc@NV~q;rZ} z$*!;-53VYkx2#A4Cv+<_Bg!!( z;O_?xu%Dg(=-PrC*)*?f1fCSFr&J!+PbQa$zN-tSx>1c)@>s&guMaXmZ0Q?IJc9|R zotV^A>+BywxAp#J5L%`QB$-#Q;va0LB?%;@V>LDIq!GX;MRI1VL#i>M_*bH^Y>lZG zh;A$wu5IV{;m{J=Ce(yA?*5rkZrS`Rea-{A9aoEIdzkW2zR1@G^?2G*m-Z!H&L%JH z;ac)F1oHDpH2l6<-FuMxAPOeERfh8?NkkXv)wX+Ko2>rOvU3lEHUqD{oXe%Phxhjs ziaC)!Tbh9K*x(y;O<$b8*wUTHRvV2>ox;#_vVS3Ze%=T!aVeSQGe5h7e#?;H_59{WSz6UW z!f_6znkPW_`5CF0XeLs_@@IIZZR@18tWrfW>6mG#$X?;~`r5Ofx4_-5`4p={WK;o4 zfcj7V$rAtptJn00Cl^yx#hMu|4tFxL1#3qEvEMNdmA5$;3hn3^1C_LW8 z_d`mRA51ICo}me|vT-3qZ*mpbgUIh`diu%yFvD>_+rMc%o!B zS{o7~{uJZ=mleNO(+r#NhJMIgcNdcVSq5gBGyrSt;HRxmHq1Cj@PJZv=|kzT^_N9D zi1p!J8SUgy@0D0b_gCnxxS}}|CKTe+ViH~Zqh-mdW zJ<0n8G7_Jj02^y9Dm4k5pc!izrlhgAzeeA9)J&`OdMty+u7BgCPq-d(l6;)E0^yxY zWKo)EslqUg`0R<2{7~Ur4>_Eu#0dOGv(%M&bZGwc{;W6pFJ>TWC6#sgx06~_h3Cm{ zeOG7~Uy;`)cZmYyw-r3JI0_647!{~Qs+GL1oCv)|)LBq0#x(8%(;P#}-IS!vu|$2K z6e{MPqa)|mYB_;^ey{~l%B$%ntZ;`PKOKDRbu8AMUio!$ zbidjP-?`Cy>3id@tNqN7DbVSva+Y;~*vt0~m*$Qoi%gF>zrG*u{a~pkic~^+LbL=% zp@6S3sQUY0Y2w+K5z02Lecb!mx5UKKa0&?caA3)spC>(z5qPIMdG>0zleBDdTfV!$ zN;KZG765*u_ZtyKN&?uis;rMekT1JlhA4e49RYAD&99{yq$C%Q>99Rnuicx2;%hYx zyzI@-OB5bc@YH|*g^iEm7HVaqE|>szpo8R&&|=J4s5;#R*5e0n8$WZAf%~sDSlvn2 zHmms+8^7eeb=JSekyvVF1`$qJd>gAjwjWUMOeh$=iXe3QIw~7Due_fGLv^wlCCI|C z=VECw4GI)mj3AFxyrVdoxXX$X-C0Ku5~n-RSy--uq{i>&1Ig1-41d&_qOr6}x1=Xv zK`8`t;`$Q%;-d0f)$|jjpS?js#PP;)#gUwe6kw=P3BYUGBpz8Vqi#k^h2scy`)Ok~ zF4LVpKARw&HKeumRb5>mEA@avG_}Yx%8kGO)gz$`yn;E+rTA`>Tm<3HFD-~z=X>l5 zM0?0rzgH$RVOMGFLAjB*9Q_Gm0e{tvequOsR+*5B8;iO3*=p5FeBg1Dw;XJ|c;|aP zic=B>4d71YF*DRQQ~He@BF=zLrAX;|uC!=HgC0K!gt*!Vsd+A6jx2qT5qT4njrKZ; zP=cgWyWieWib{}8i^j0d5ZDjg=8PVtMelj+9?m~gSka4PQ7}#+gChv8d}#Trj);mx zG9})XvOv?Q^h+aP%*VE*HI^KeboOg%eXo=4;RMfy7dBiUe> zgN8~aBR2#hh!u0gOx#&Jif#&8qn8bjXSR`dg>~ZP5o0A&!>5_{7C#!M9-tYdfzPIz z>RH+mHJ2C+x1rnV)yVfgglX9$yFD2F8ms@6EE)eMS;$O3fgv?+j0Zw=8N2z<_zKFd zCTD=s#Ed1hn?pRYMZSn*g2EPKp>)fO9Nh-RMGOTm0O-&k=|Q|SAt&S9NjxoUx>P0z z5dp8PqXY19>C8qX=xdtIy^1zy_r8=p@cfOBeDhpN*3nLBhqiP;tS+(q z=#5>iDq1eMJA!>;UR9G84g(JJEB!!#XLLegS!D}@7i$#iIayM%jm8QTt56~FTnr3% z9IQlPp_Ik71N8$sB6Qq2ak83*`k;;n!&%nbitm&;rK~yc#7re6)H6v!`dNELhsHen zreu~Z5PW_pR@s-kw6yc2;<0-L+>S!Xz*BA6c<34YvYqCR1IrVB6sj?edU^Q)FEyF4 zr2^rLyIsez+0o{54^WSy#rf8-`ebxikz5GRrkpK`LNyPW$;@jwI0@XtR^@ga z6Ow4C!1Na*Ye7FQ7Laa2vggwlsstV)Em&44SQD4lHw((j{X<8j=PNr*;~r_*P1X4) zsrB*sux}rkIl=GzWAR5ZhsfwYL9tYQ@oPteOEk3H_OHMn0+o_S7(7|o9Ck&^W9jS! zX@=u1!3(ukOXKLkrY5rT^!#a&xnK6A_Ni(1lTqwwI(UeoZhz68tnUK-JdyjmlV4g{ zDOl0cbjSD3d||nw#*llp^t|f6<1=vlf0eo<=ynWFJ`x?8HibD9-oHDS#|aC`s(HmLDxF65n99aA8~3@F^nO7$S}skBKUN8)FkK!ebG) zPYBE7u>7fCp4D;x+{;hYF2!TfW{`+v3tU!7c79=vW77U7@q1wuOz#MqBVz(r%tvjT z6B9(&VH!f-_dfVLPL<6&EMzDWMYvfO*#?;@HzQwh5+G8PNihN*&%0zRxWa?G*?K-} zpt%*!4no*a4~jm^m7O9?Sfm=n?*0W+%^+Gm{hl9ygAf~4=g%AbH57@q_*ZOjGF>Pb zqHrinAp~1LrZ^g0@F@Cs$omZ))R|0$)<`Ana(9`~$%}d865q>E>S4vJt>#n*6o}hU z7vhDA+o7CVLo#6L!!)*qC(QK6y>rBvm&!{Hf9iq?whI(n_Nu5po(grt)97m0P8-N( z)q`ZlcXVQTv%RK$g??Wk zd9NX|419R$8_!=eiYEcxUtvd+&Mhyf`3O-TY(Fmm%kMS*Fg9H&@tNgq=gE1@2f^e8;}vsd>mOGU~c4cp?~fpV1FG)UaHc3t)zk zmY?=o7qHFczZ5Btk8Cw-x%cWJ<)_vbY{H-R6gbk`91U;NK90X;HM@?&nGEq#k(aNK zZwDVM@65IVJEoz9W=Rr^QYt&W=+!}A?)=w zE4cwqPz}=xagQ%Rn;u{%{Ts=`L4^Wf-zqAEo^8q!RiNNls~v(q%ONLH%iZZ zoH0VOq|Tn^J;)Tnu3c&j1xGgxI6Auk>znQxy=UvVH9C5oho5sROnkBynDsP3={BJw zuJ3GjimQnWD^ncDSlOmvoNTm&V}hs3PeaEY9lq+H?&oKHEA#sLZ!~#?Db*PkFp{J7 zvY`q%uSBp^Y@;Z0li7IswOboPEZ?$(h=L_&R@$M zkITsqApJyl4bqxsv-nv|*!Mwb2j?6UxcgtvBW@HD1G8_W_`Gi#H%Jg0wYR<0miW8EnkbLdm%l$C@`-TCK26v@7Z-@y zHyK2LH*?R>+HtX636+A;KqA0(RYkwY_FIQ|6I)NHcHvJTSWl;eE4>Ta`Kq#MOkt== z1q&u%v0qH_Nh>hgkz!h(J}t4~AFV115r*9xSvN3=w7eQr`7u{}71*{&=LhPL_jWPX zo@z^pH;BMXaP|DTp&l4WS#rd;Uldm#fl%c&@!(DWt(Bt7+W$_x#V_7*8kBoJ=FzQlN9-lMUbm(eaGz$j`P9 zCw74EzELKgsm^QMeeBSY+lz2Usg)|Co~j(}?c85zypZTbsa{5*sHj@xN+xeA8f$}l z@}!Wc7V9!8?|X>z!uxsk*EJo4!zv+^EC+@9oQ=f!rwm4+4LZf_C+w5dH8UB+S#Ikp z&q0iw%9yww-ti03G&dQWbI}gYkbAw|4CeU7n;FfWP32D!M$hfr0R+oJW767Ik0mTn z()aodYrNohIOnNurA(7IufdJuIP|_c+ir^^IfIsuVn$*PYEz5T!?&Bjh|uV0oJJi} z#w9SR#k`Hkfh@7tTx>@gOqp25_nV}52ul2p3eFzYY|`QyNg8kwRs*BFj`&|X@y3Jn zKBev@HCj&WwN@eJ9Tvo^L?o#b8lNls8iM*2zBze$o(Yi%weI6u#j+Q_&+=Ntk!dzY z049uN8rirBS|jLHxmli#$B7cN7E+;g{DLVs_QJ{HL+)@VvJl>#a$5xs_^kB4V2C?ylV?)jd-dDhuc z<4dUFFw6*o8d(}By4;sd@2wv-lRN!-HP#o5g^NUexnJI*M1iI#^XW0N3rA^yW#g=RVpB@5lp`o);;#}(XEn?JB| zloG!4a=(GpCO9rmD~lRoXeTw7YCg5em2w18FdMJ0v`}#5x-YTin zl>rig0zOSqmb$2r!wn`h3zLK@&(}L8N`YTBzA2OYMj`CMl%Nyq?0nbZey`>Q@ZOWZ zcJN$kBM^nWHA>KyR|qqp=z4TRNJ$Wh3D7&6qY=7SkAWD)m3lwL*UDTDX}&IV)l$4ehtbEK7I5mt>>79XaoZYLOcI1TOl zcU6Cf!$r{GaHE4bSQk>{$3)A&X26G&hNvT0CKrCG_?t@AtB!7x3Et#G*50YY6i|YZPzLa8?kqhIfY-{6j^)_Ty|UyjK=y7hgKx+K9FC z@HV+{ku5RoADx|dCn^{EqTt_x5tp+FdZ-&rr+DuV)eQ)GtVaoWIyGdvM#rJY{8X(i zfa6RCy*B~o-l{qyl@-UN;K0x6Q7P;?3IDaQ2~qhKgc-=gOTGY{)|OsM76qz7Fu-)8s|?_S2RbGQCkKBJVQ zNL!EG^iN?8ABOr@LC}V|$9D{u*2Z_I6J&lC-||!t=94H8#sQ9Dm6<}7w*9DuthMq~ zRhD;$mdT=ZFD4oRUPAInr(K2d2f16^z;Mpd3?RP*f>#p@924JnA$V4{bTXYi7_WAa zN7v3sO(9n-$XYx%q@P0}*JnD*;f~%IIfzz&Fj_m^kN)SJzEvhMl5oQR zWdXn)md1UP8qUzZ+4IJyrYn^5Y|(n<+LC=!5Ghw`t01)BaakI<4n+5vJdukAQ=uWF zni9F#JLg-J*}M)#G8 z{hc(eG|Y+GETL4u9O(6_kb=$DlL6`!0%2B_t+^koB2cL+>(SOQ67XOMVZPumKf4w0df`k>O$_*T{{S!GkLY0H<{9vP*z z1?Sf7WSJROW?ozFjfRT*XO#mk*7~=iB*`Gpk_X}0IhQ=83CJ2`;-KTwj*d7@>no2I znWxcPU?SVuL;~HP6N5c?BI4gkLslW0_IV-77k}%7X4!nq3~90ds97)%pk2@&WmLW{ zDOcZii%rfyEy;|qyEG8p`T8DVKHBdxe*@UXjF`M7BB@n%rBrk4)LmLwlm0Q%vGSIG zL)yRwy`(t>XGXME*2hB-@vr!YTt&r9m3u-{;Y=AjiT)0CBEYo8roE?HMi(js^jru1 zrI+lnHO8Nozl0o!UD;n^*TfuOpilq$ z9sxEsY6z;$vhaU?F zVDo4QjDZOU&+ynlTYfzhP@xpxn(IjcO7x}vAM2;Wg}}m4Ad{2!;3+Za0CVv+0P)jQ z{@DlVr~=;EScUvoaL!FA)xlT-)hW2;6o4AxVxuo7r%b^r>^Blnr?8I5^o9PaDsHhK zx(V6T2Zl=KnV_Xg8wVy(Us6!uBsPVeYTSf9-CCcbZIKG#M}Sg#V=21;a!Ct>1b9~p z?^(Rme%RoGzXp^O7s_=2!xZv>;73+Fk&UI$c$T6wbJc)?TP-Gce%m_Y- z35%U6Mb@{>mWjqyy7YuD{TV#-z0v`bzjnkesuC7_ycdmmr##I0S-RPnRxqWs*ZLohoQFXr6SIH&Vf z$$ov!EGnu1?h@!{HR@On3xlWNo}MWXp1vOuIaq%Gb-zD8v?eGnr6veai5~HNE~U0S z+FJF=Qg}T_B_FUSRA0+^pEizeKNvl*4WMc866Ze0Ka`3jdVk)BV*8y2OGbRZfHaI3 z`D#FP`6!?U|G?d+LESm;bK0nytoS&#w))E}%P9cPn z3#nWhPDKbr(2=FK=@e~43!&+~6*tj2AkM^t!#GFBEiV_IrM+y9}Iu1 zs`o9mZG6AZCVRTBMQ1FS2+sNVZOQavW!n^}U=2Yp{Yw98x&hCjrE0(Q3id4>g|ak3 z(y+e$;7e6@|DI^N#!rhTvc?FL1jq#UXC2`%YE#`pH@~rg_jKb9W&B1Dps6klvIRcJ z^yLjjgmC2*qv9)EST0b-t7BPWux&xr`z{5X=PANYA|{hc26wEvU~E4cEmf~Fxq=KB zJpTIoTQQBp8#MV?k#xUMw^g%?F*AcpW1+JViln!DzI#@&cEBtk{Ti2V+J;Gb^L)_} z33!&Cuhu(0+z72I(1|Do%z6iiD~OvUy;8AhJtQ0lZMOYVk*zVPr5Y@3L6F|@jVfiTx_|Qi@m^qy*Jz-w(8^<7AW?q6Rutz zc(L%}UkwtozSG79x=X^Aa-Pz$DrZa%3mIr5nVxltn?|@r+0s@u)?yEudCPh=t0MHOeqiuZPgnW5n@wyh$%v(0F~O7E|PT?wVCB^LHc*L;k79{=y= zh7uR_gfNmh9lqWR3mH>_a0;)|qzR7Ddinrj+nwS_+zDUTG zW0|l%+WQJa^~}S8Ji(hfv6v*zpC79PycvLDC!1*a1c2kiyT+gIl3&#WQMDqH_sQTv zfVQjSmBC}Q!2ZyNaChYS-GL)rL#6zMq}t;tZn&)NEMW65O2G-)Rgt#AiOU6qD@%3@;DrcDLXga%nv>;b?Q&eHinR1ct&>>y*s)~|2Yy=+TW+J+(MPb>=z-wW9ve#A)v4=cH zBV*;O*+EY@3ya9vch#+5T2IWXLW}!NIOG|1uzp`A+9i)Wj~Yw*=X11{oO&aFtUW;- z(eEJKb4I+H7;An&OF;>p<+eM>DVrC8W;-ujrT2NKic{aPP{z=#Kr{!U6Pmm9`BsmiUtD_@6e8)I=cL~f-GD6qX2ep+TkqyV z?On^SLocA;GU!o$?%5NEDb#eG4x{Pg!4nyxMUS4D>s{>4i;(h-IKewa#SDIqI=5ar z7j0D=Oy(!qjefm?V?rmd)|aQ(Esk6 zNF9DXzxYsV$+3-KV!La+$KEV_xqYWe$GTFy0B&n3>tDqFWr^&5!Ad42rklU*y(uHT zEj-wECje++zmS&pk^UG+iH(@Q}Saj`-s8P}@>k&kHUFZ$+|sHT$pRJOgso zq(B30{D6v6wmHCEPV@hiI121A)QEaPaTq-}{33f7+N)6OP8k^28BRPN6>!bR{{hz3&V{u&73m)Tp3Te-!O z{SFAC1t0nSK4Hm3G zBI}Dv;Oj3fC=_D2@I)h)xJkH-Rc#v7#n&qyon~`6mvRgHCrG)jkjze;6K1M+mwt3X z9dCwev|?n6gK{YAF>LryssU$O9v>CTJI2Z;GiQC2iIfgoruq?oqMUr`0CnvUJApQ09e;k=)e&<`R5EdUM_bN;O0 zI*3@C;_LiKtc-Sh!9 z_FZy*4Ar80fYtZdFTpdnJNsUgrQ>ys>Wd*BG{39ze=3@_D0J?^VA*dW42Y4RwP_;` zc(>k`U)9`B;1$4tm3UNb%*=<8VlWA7u|PORRI0VhU)3n= z6(F()=Ca!a1nX(mAv_w2&4@+`aTatRKh4qubTk_9JVO4Lh#q$Wvy$kJQ5i!#6w~m}6NO=1%C`WYNVcB9<{C9?02JNu5jP|RPIgMQj30Gz)ds|19{+9aCvaDcj6N0F#3*m}8vz#_ z=J%&O9~*RwT#g9ssLD8~Ui|wIVIemSi6@h&U~0~Y+6F&lj)&RrAhweqq3aKOGf*%(JCOUPaFGI$D+tk1zgqGB=ROO3 ziBG1ZAT}-sp-b2qIuv}DHO@HtW~eA`VH#AB{SxFh6E26?u4oTfUh1Qq3kezCl@FM) znrHYRnF1{jCEo#rVCEf$;aQ(B(jFmMWBPdLi})bAZ85?*>*Qr)Mi^e3Ui$w(?7d}J zTwT_`i95k95G1%e1lQp1B)IdSfgpvuYj6)92m}xAu9e{K?yd#QAy4=Jo$2Yhy1&o+ zk?T5CojPalwU_+Xy*7yi&n|-45iU&Au+)86edS#z96;YZwuRruIvTd6tPzz9nIA-) zZ+>t^AY7?W;!7W~v>X1K{kMOh6u7|$2kJDbx!=!;N_aMn713HG>4GugtGQj5hwHnp zO+#X9E#r>3d~+rZSsIMzEOJAHBfzG$zu+kX6}#ONR^0;dtFO+Iq$8z&u-^{tDI|7{JHU zM~fJEU<`K+cBuZ;nb%pPqYB0vg2<9ny~89j{;MlUsC#W+8VwcNRa!+j3Ux>0Y}vGL z#L#i|EzDGDr;Qabz#LGn8iICyQ*{tRUIv!;kW$3P!2!ZUFBK9Yy-L5gpR0`1IJR0$ z+D1@r87a(0fcdB*0!*~((0(n*^@CKh>k3U?34=E%3xhl8JhPRz9+;^YldLdI<(&BF zms2}Ao^5`Z@<|$@Z#-lcHLTG5I&CX*m~|#0{MSM}55<`rRkQDqe*cg4As@lvkfOh7 z8oz0B#qKjl2lI!q#X@=@u>r`9fzc94b=5qQiJI?w=*w-2on7 z3nY<)tNllXsxjr}rvlHwm;SV%c zc9Gv98-39kB_dp%!GZ_#sX#a#%NPI1kljqz1fuOjXdqwVwAdwZ$1jlcoeFHkz+mr# z@zmNT>!TvY=RgqMlWCX5`y?2P9pi)gTbyXI|MsnN7+oLX1)UAH4d&X;_@9vbKsaBc zSV1i*sXiMhz3$Rt7DkCJC-Eh@?RcKT2()!Gnl&J^4NbLBpGP)wDvqqU_puu$7QUFT zpD*T1p1Dp#!%3Xxx3X@E&cp8amhRL_CARhn!|{Thv=z2RGjx-~@tgSE-HJ=v%HoP0 za6-!YD(3;&1+5Ksg!5<#;j1l#Tz*&wKm;9qfDbN~-N~=AFh)|-a`h0|2>fN=5{RbK zSdE|iV3HYtz9um|jj|uvmCQeZ7{|>q$_GfTMt*tGX{%y-dey{RzTr?4l$+{_9cr$K6X%>z(e z)F$$X<+kp&u^Hng_k3t0-g%OwcMJ+vxXdF}$3Vr*i;bhJP&bJZt(AG!+7c@D0xCp; zB7nEFZMsP`)?&_LoGrm3hS1sIuVFq}v?DMG+Wc)1bpdh2G};`#A4vnoj*gs+1P^$Y z5gqcy%@Fz$+g3u?yD5BG(y<|IA6OlE9`PT+dnfjl^2hw}H{~liKh;hi4(W-zGDV^{ zVkAYx3VxbU@^t?CZgbQgHtd)(Op5|=j6csdZjid3%6orymX<`-t{U)P%>kKMcvXCs ztxnN(sOt^oRG)8LH(zGMGToLFWdfE6T7t<}5_P4S3IrPBC!iZkOC5;m`vjv0;{<5J?CTAHR^@omOHRB?h}J8+a;( zp_UB^^EKqeyb)0HGIS=*G8-${=t;^7P@;acoZrO8zJy$WGphJD4aOG&HCNO9-QTqL2Q^@&K9xWJ zqXHE#DcXZWoOKkirlkMZ+o=4nAw6P^@ib-W@#eFFRaFBx$<1*zR4whZpSO^8-v_-R zB?mgUe0=1OR&1^K1Yqx&G^cY%q>RJ5;IPf!A+a$?JKO}41C`Dk^37F>is3ilkwapp%b`_yn-rSL-w_zvh%C$<~{tsuD ztGz0^v8SdW3VxlNeA9k5{M-)r})_Ovlf6aIRIVO zo^sH-S!+I+u8Kv~aG+^1Kiu=OMX)Fpc5Wx1gz8MtJJY54@XlTRHq<4jO=+R(I<5oV zoDN)MpaP)@By%(uW*W{o>;52R7&4o?;wBd-5!X-WoD_#DeE&OE>MrUIK`l25YQraS z<^?pUhd3Y~E|`izQ9IuA&fH#E6AHESO+B(39D(0AQI0(B*W?ppg2feIE9<;f_fIYcdT&T2*+@bNt!c|OUd^$ znBFn?6v;ZdMwaCtL=x5c#t4; zZM-&dTK=BbbP-zXiHw1CG}J>MFAGxS>LvQ5WBX~w@?~G;;8Jz531+D-A?D^b@|$<) zp|e~PK*Baql)b-s8|e+iyHHXlogm=%hH=evg=24ZkpfoYO6;#;vo09JpZ;@;+^NXFZm^pAnHD8fOuFRP)JeFweZRgl+s<1)3F!rOOH3_y%QtN zQ);DI4i|o(!R<}kBCpaw(Ou*3@TJ4A`jW)Eo(wq+84%i_Q|l2k-K*vpT!5 zg7x6dMhai+!j3K~5hdn_rI`5Aw#ng}D9ugGsr(dBW*s(3Dyr@T|CPkO;EB@nd&^&D zc6OYsR@n}Wo|gd*6&EN+U4jD_>C*9d83jBSU(YQ`3vK5^c%s%PYJerPPoJOcG z<(F{98AKk3rOYWR86_kuZ`6m=`pc~MwoeC9H_4?a$1@3cn8#Fbv^XaR(i3dwiSO)9ew`H&Hh%SDrE;t>t%E2knueT zu~nlb!*cni?FLRh`Kk%jbMyKoU-fsP@{elgpMMz9z#++p<$WgrFQsu@5O_PL=~myGyiZM(BD$sdw>P9u zE*kc&W{jWFBgLt2y=;GKu9p$)RG$u&v6Vi8#{-ie17$4CC-J4y?W0}Y)VCSS21X;8 zvS*|Wr~{Fr$DvP?NNfgB*oWDkJ|v69hG=J-hWj%Dy%u-v1HpXx2 zL@lQY;C{|})vU)$8-$PQr_g^2Z$F=^m|j|6`8Ut01L+bTTAc6&K5{lfI`)3eOTM^M zq62PrwJzMo3=V+^I_BsdzzQ;vIkl@_;>n)i8n`-=UQ+P8g6+)(r9u%$^pihwm%`1G zL$5XcNgn>2FCl-w3J5}&f!_E=cd1u9fzC7(mO2|0zlQnLte2kz1(ATyA=S(Jj^)lx z;Rp;Zf8P~((eFb#R==ZAHKR7Gfn)S|GD_2NA8Xz2#05RgN|hD+x2*DCzwoqFd=-H9 zvlJ<1yCF+AGayz+RQ+&JnH z`+V%y&iDc$3Ec=>))a-}uakxn?7TvEaF_6JS><~7@_;gbIx7B~XZ!zH_5b+e-p>!Y zQrK^o>A$=l0TCL6Xe`mV>-&g$02YHKj z!0C{Qe#ZYVuMZ3ao@l2v>P*ky8S?-1V83Djuj~LeY^>|QyWYqVc%nS-?AFr%^N;=W zQ!b%_SLO}%Tlc@b9_F^JdHR1n27h7Tm6c(T^P~Qk*LRA&7>(Ls82m1pmnz{qITepRCdUA5Q`{z`qlD zI#W9vHWXHe>?!-Qym0!i*IWz+O1GtU{YTf!zuNqNHDDdz zU;6{@{mX~pi9GJruD`JADq$dfylqvtr=bKaIs!{2w>vHOUmk00O)vN1db5NPwVUC4nJ*t}1!A!^!@6BqdD3dR8+9Q4Den7tU`Rlq{~3^0 zJl+r}3q5{j-)Y`qdMWGUdMc!{*_yY#=6LZ24Hbkf)vDIz81Vo)6ZrdD66Dp(@AaQy zg2|lW{~nU)v+9p1zI&8|AIVfLQ`LpSh~`BcgFD@=Kh}*Qq9=IPgVXB_79wEJF^%Di z0P4QwsX)UmLK`|lVL;6C`@`9) z?$Y|~67l@g-j_PPp7+(%Ct*tivH~+0+qe(iE_=xSIgf{yy&=S9hD>#rXE?N>Ux<|ZL&XEa+U_*?h4%xKCXOtnZ42r z%sW%}f^3k*KF3~q)-s;}5FsY}_Qz|J#;s(=X+VSea}NFBVg*>*k=7GMcrTMEsybj$ z(LU+|k9Wy!MIW+?C=zzHqp&;!z^~xFZDNJ4=`3=*uZ=w`wAK4+?i&t@n91c>TTZ)7 z0Ok}^+hrlE%f+`7z-e{|=&q6dWWHWSydAUaM-IN85Z{qh_TG=n=gDcuX`1ctb~2qK z3?KKkducLk)tH)g^J?~O8kVKLa>D?>radA*hM!>@z|1~Kf@)lf#{T~4C`cNEhkJtc z06~=C`RU|Y7^RN5@vZN}!U{e>CXh;80E*iy@r(^(vK6mkY-9MAbw@bCpKZoho}YTx z?{<6zHm{DLdEjDHA2(k9J;E}8U`o$lW0iZK2M6VPRQIkmKn0H>15BRG&{f zS&=7RJNqVuN!l#0gm2^4yUCs$&tiQc`L`E2&w4EvSto~65I0YO#YU ztfMC!2eqtf+E9crlBrIkpI6kcUp$N39w42@-uUhatk9EsopzdZ!V^UGDD*2J9ERwI zL#ca~SM|N_mFo=jXc%`)4s`2&dFbmvw54BlJ#RxG&(dfnCUXuLsaVxqA-xl>?^~#( zt7_C3;Qfss8Q1RIfI4`-hFH*m@dn_aX7vIqUFD%^gpv%f5PAKRfMjQR-qSLeOwn%? zrJU=Xi=Rv#2IS~`e0_8eyG1a?`r&`A& zfQa~2&=S!4q{jp-61(pY=^o2)vo@uTkJT?p%cO!B}IW%MjAJ+W|sDFgcBTOVxhJh6;`m>3*&g}|hGkAt7^ zOfh-)>aFe7ls2o@are_FE_PmMp7dSt2lMA`-gf$znSON56y2@!YNdoc(AR(2=(opW zx!X~wP}dY+WFlAoKEkOHgbtw|2|yhqV=^%ift6jiSIW4KB=WuJgqy{DCv_DI5Gu;w zZSUqkNco}f42%9?Zuu1o(|GUDn*f-`(%P2SN)RBpqiq^nc=29-p+Uo)PXy#5*~|qw zx>6_iXzsNGD9FeP?<1SDotJ5O?laBHnl1-SSC7CW8CC1h(nzk!JO)e!1=U}@SYwhuq1B)z2*%bQejAmYE3^-eECw?ys71nG zQt#e=30$Q^ImWy52Gag~^ZdH*iR^jDH$nvAd`l>iKsaA~eG7V|!Ce z##3LX&kIn`R8aj@#Si(MheIj&9dSnkZ4scQV2I(NJfo?a$j~Jzw)e&ZvLhioRo!wI zbHV(?*(2m_`EIw>+EaT=^I8b>EOaR??x#`5{kX&G`zXJQvGj3o0z6p1aKY#9P{w_R z)*+tod5kY1LgJP1tfgNPcR@SnOMo6l4r7_)?OI!4=se0DiKnesRc$sl7{KHKY!mH6 z0K}biGxg|KjonxhWA)wB=baA@^iSaM>521V2=sU>&CN%w2zJ~eiZVmemquzX3g?{b z2(27l64Xu+x$;{iIZiz{djA-2S39OX6?r+_6>m zRcQwvt1q2%uv8r5i)DhRhN}lW<-TDG@69l0g7ekAm|qnJl*DqY`kb}*1h|FM$w{Q2 z~Q-87MsbpfNbYP<&Lkax^FJ-4VeS)ndcy zex+vdgmyuEgubn~-9Q7EIz+DV_U6JT6K94B*BcOJk$DH-6veuw`%3!RHSHBiZpgvh(vQN_ddW&nD!~&$*4{>KeEAvY zv&m(%{f@@I{E97ux+^8wjt*B6(Z$Yf^Po>;(=lTohAvmaP zo4)sItn^tsA;W;q?Txj~cAEVIGMH`5U1?(kc*~bxnooSbZY~_RrCVk`%i+g=|9II(T1XtgYU7qAr5(Vx+Qw;fRq-u4IN@$IdyCD4}U6sD`4V znF3pj>i~t1`542}nho?NRdiape8@12HC!>SHoo3e*ADe-#a!KO*SF!lTGlT+ zOkS^+XJvk2ewqM8W@aS}%XbCVFWoStKDY7f%PPv^u-RVYvJ(3p0`@IuG`$9Ee(j&T zS^zA21ZUe>bO1UFGQ1qaWfml<0@tRj%Ho4YKG+Rm_*<6SllWODhEHX~`q1|f!3i6E z>x*HQ=CX#nq6`!!epRMXEF|W_z&6O1$%JD6KKL6_;9=t`+u0b zxk>)AsW_g8?WxL06Dh z8KHo^Z52?tIiFJ416HS^*UX9cO*8u@b^_VnQLgti+D`0Y^U71NFQngh8cfZAid}06Dd=>l$FWy=l2C?j1$QwlWXrESr6oN4Wo)B?^hH3q_pgYuO939yRFm zzL-9;^GLI-A9#4vKoC=B=lP)hiSY+$u{*>n%{)1r0(IrKk9Rw^m!ooh+k1AE9%~sB zKqs1~FfTtp-5eaO=S8wam~FkVbyxA?Y4;yC$e!Q*m;-#BL$ns^eC$_E;U*2GnJ;q+ zhv3N`X8XnAf@AS91W!dZ_@CD>e8V)wc!CR{7{|6$*O#n(Pbq?EIH28S!UrG5m#w?} zP(cqsDmu#_or9pEta^w+!tuBB=0g%W=XmicVJ`EFWDoxCxkQIX?mbT`RVymR#4eZ) z%-)r^61V(#?ABlX&LR3H!0HZIGniW+&#B|d3fP~Wm9tf*pEhYl=t)7F@m5UzG>Jii zFTB_@mUUlOR2+qEP=1IW!#7Agj+JvutD0#;~5HMj{QYUO(=(S3ekhxeKtzH zIx*08bAsM&J<1B!0N$n~OwC7Dm3!JXZX(7@<>TMCU$==>L`-Vr>i0_yl2e2;gOWOp(KpCQDoy34*me`dsE^C8W7PcxS7EaI0Y zYjCw7D;fuvRM7WeP|05>ea=xJB=T#@1z^BIT$vAmQ|)h4)bB{|nf>T>)|*dYG5>r? zZi=zRe-lk6VqggV{AfQ*#wL7mZ*9xYvTF(P2IeLAT?H!O0|?AYvPJhI$T=%vLW_15 zVrsTA>)2cX;lb}%q|k4Zqb*-8J&qV(iv+n98nS0wlbusm^_vSB8_*N`zU|;a^_1*` zdracPkr3Y|M6*YZ9wPi9zw}e!0?vkP!xHf7Bkgi_z^SIf!95$`9ELkl@Il1lcr?WS@Cv}!^*a_!mM~GE{tDHt2dHVW)gRYACJPih zW#DFknGpm#;(a)M8&PiCw43N-SVvr>Lkt{hP9JsW^116L+~Pp-z>1v%Cu=hM^y@_| zTLPl1sEbtl!4uEvq__IrE>~0&zG0v23bgs?9HgKtx|ogLq_}l>I0!ofF-S)JWOIVS^ZM z^w!Vq>h)XEaQFk61D69{tF*db+9Vq+u0{6R6jNn*25yG-1ZP-bfOBDC==m@=&9Wo( zk?errTwsV0L#a)uT`lrfR$H`Ep z9loD~w>HeWX)+~NtVLhznoZ}1l4>1lG$>oE!Ge? zDlYPH*|dk1*E}A|koE9iB|hq+T4GZ4LRXUsz4r&@1iVl~&p^1gQi5ZQX2 zi75aPHx|#ldAvZ#-MVW)wv3bbp-+&A^ug>J%{XPYN1UZfZ1s(0&LbX-b62)!U-VvF z*K0`UW;@UrkoRS+D8qs1T(ZI?_?u~9ht%!U!%5^x<$6Q~iDdiZs|Ccujt`te`~c-6 zvIY#)^A5bNIx+B2y^Q?Va~+@HiB+*9f2Uby3Bg7ZVN83yyG}Lj>iP5+6}c*dfqN%B z`*UyrM-=kOKzg{t52{JX{mbo>qIwEm)v#M zxPKiOqR0Wwlb;0XeDRyv_>n3Hg@DP58#GARFmn{jNL4RUp+@x~(X`q0D{3qmy8NNB z1@`@ZbH=FVK-tXy2wlCs+ZcLN*FeY)j^hd$8Eh!F%zR0Sr{gTS8a7q(E6 ziHY=%@w8xplNKvJq-@*D#&fij*i8SoS&AiJ67w@`t7Y|4u7tFwpMlVh>Wdp>G$dK@ zjuf73wyH7j4S!*&lcXehalFV7t{F;VHQlN^ZP}xY^_x9Ycc1t;&>gXPYvM_*rUz+i zqLnRECmc48IlP_3M{;RVsm%<9WvpPLh>a@K{yw&VOS~|dp|`BTY7@h60_6#fJgKKzbc zOeZ%{^pn_1er95&)%7Kup>}#bWkX!OLXq}!M>95 zeSLlhj1P$2Kq%Cell<07C{Rme`J_tf9VfWwX)P3LmJa!i4&7%O_x|vAYCH1YcfhcB zaN6C=@%y|xiMx_GK%Na`zA{$G)w6gdld%0ledJ}JKa*KEc(Nq5w1<-4US)uHWj#{L zzNFmN!To#yuP>gSTB91lNxO5P=3)5MIK!?ijA?)QW||HAG0A7-wXW3X>uQASrfHR& zzpZ+~Bl};gLPViaE|d0qnev0BOzzyU!C(Dl16_s zL_UG;_lo;Lj~zy*>BaW*8ietP1*9jV9({sRB43$|6TxDjMswfT#6>NwYpcBvGzT-dE`*Pe3#M{T8Tc~>y-%rRpLLEhU|6wk(RCqR8VXoXObA7pd zWB}-sJ!d@F2a-%UGrHFwN5Tg((rMXHB$dQ|!or%dZGYY*H?w6E8>5$x(%(cjlRCE$ zE@I|F5V=SLOM)5?=M35o3R~hkU=DvYtVa+zV|l~g;cT!BA?CaR_I6QgiCLhRuy$7G zH=wtEf&XXxb2z@Ux+AVwkx{k<>u9P3zKK$&N;Ka9oDK)Waa;2utnKyO8A>`clj}se zLV~n~m)Qp3UR;F4@NRr(TYbi3Qp$OS(;;GT$8k5w4BeNnWA_WBy3d$i%eg^y~=aE=O;p{Xu|ev#-+GR*Pc(n{+yW z%@MOLuN@zX|7xtJV!~z*X$1GNG42)E9Rj#O!I5CQdz z9&UZ6-N)n8XO*5xtQ@E1yHDN4H^JW)g>Ct5tgL_p`Sq=UEy%XC&3Cl!Q^2@`9) z2A(iOD6!4Diw#a0EsB-gn4fxz3=~yozhGA%JtQU6Uvvkw+(c<0?;ON8` zg)36ax$z_~z~!-O%6W52V*4F-d=GWD8Si<-v;s7PL?+~vTUK%`dwh186u9I(l|zZS zSa-Qh;*HZ(nn{#fh&p28xm4yg6+Kd~FrdqtRqsupS@^VXKBM@Db)}rEDty(D=KCf% z+p`hfvmO3Z92AR|Ul2_t=gMPX`=mO(O+|lGd?Nltm*4p@{HNGjKTS;Z>k|nw8bj(l zzOS}WmV)NvPoqKuf^q1V?@!glLGqbcS#>~(ikN^o3f+oF-9#ygn zj-;N=gpC%*eJOsZw~YVH6FMb@QNKc+PxE=75zlHC?~~6W*zGRy!#s+^hic}Wcq5Tr zNjMJ0I%oTiXNW)BVLW>=h4wmzkXEHa539s;Pd+Z9h1FZ-g6>38AU;+4tVvCL4PGoF zN_l~Um)#;!#me~fS2C1DC&HSXXMTs2*vtz`(zMK2R4fmJ-ClNS1l8^#q7TCv=GNbi z|0y+;6)7YVQ^MT2ecNC@;gQl=Y2Ui{1MFECFZ~9&o%V8_Vl(H?`0=HHj9!#ilBCaS zZuloT-jWn{@V$>kn1T38iY1J5CH5`5biwTBW`v)*Hs7Q(0I1a$FDsicx9O(I1k?@W z9M(r;%xXwO@ zflp<`hd2vG2E)Y2OmwjMO4H)k6>?G5+cr^qeL<~o7f$I^#G4$RA9etpuHC^v`a~o| z`I-6yns=1XfV*0rZ>7j2sQmK1r(bK75)t(E{R|j?AbpSc4uFLBHfi`dndj*`cHVVg zU2(P{K!6cE79r*)%vYNaPmA$(|%UO}h+I#%8vj^UGknCy1Jg0q3 zMdNi7MZ#EA#utpux~}u#_tS0kV%0!^E#>gFZu&!WDhW+qHJ1?NSRKGn&ufV5Hr?oT~(Uw4Q}|tUNMn2e%)5e zM;?|$nhuMObqpZ6N9eCAAv$eBH!>`4kZbh*_lF{qAK3e-Yf)WF_*}>d zYP#FDU{C(Cgv;e^$1Hg+Tj3k4*y_(yn%cdmly@|oOEM<7k{=6+C%Gyv_0OZzkJSy= z9hmqjoGz#sox;}ad7j>e5+HlR%M@{OQz%S2T#Rzb>C50?Qz)u;(7bh>VN_V)KSUYJ;2^LZe1~AJbu2WL=6oq|591sW zwpObY_tTxQGH3B`0;H6#G?C&wXSw{nuCu}NSQDZtbQFS$h1fbniJ=y#PK@anBDtB? zu*~cWpB0{UQjjTse|B%489Mp;u@=LHlePAUaqo6ema3K2K#LAdm17M$g1Ys~wgJ+I zX&$Wf`>gMdotSW}3g@bSO&o7h=t5P0aUrJ0%gs)8P8%*!PwOlkI=TM9y?quI@YVb& z@0pF|K#kSLD5EZ74Q<;S zYj7{Cjimb=7cXjQZd;8U0lY}}VjgGDjH(Iw6-}xLjuWlr_Z-5K1PATgleHMGlyMD@eJow`E+f{Hy`)B_hW}pc|EKu%&RKx__3;oJ+w( zHn~Y;cftOQT8y`i8+NkJdU)?wS567OdHcLU5w>G6*CyriB}y$M{+OuzKr~qNB|;B? zdM6|aWsJr*d;pB78^*N7*D-3VtV*-rDlSZUr9gedK}S0OF9Wf3Rx zTGO?RcInFZe5B@De+fZ9q+AXILlRj-I5wN5$vnMizK>rTcmuT7y*0Ug!EfYb>-%f^0`~tAjfYAp{P5mDNtZmW%CUV8UICCmqkJjt53Z|R-`;xAZ!-#@kOsMj!b63EO0copfBP0B&I z#1cWyf?VSo)RPhbSaC`>9Xk(Q8Ln*Bg$7N_#5ShNF|;Gj3A39V_d&($C|iKmKS);Xrc05$xcnza3DH$j*eK z+=M$(C1{hpvUVzGprwAhe@d-^PbEKxP>KUhlX*}!U-k67uigH-T=jb*9_U>Iq;y!pQJIel7NzlmR~z}Pa;Cuv-`|ZTt>C64V81s9~L7azeAu73Ki9(_BUCK zC#`K~*5aS1l^dDCAAMu{7MGP_%0^$3LqK@(+s)ripU`xQ9vwdCx>MMleC{Q?GM*_L#2l!-^e8_pZ~Y@-uur?{2GFeJZz7Jk|5a67e( z^AO@lrIVy&@G=!Q{>x@O+~cGa^DEraoT}2k%fYRW|~A=zWqQ zVC!m7MZTr*9XLEa`iL-rnxLCXT+6w@+~ajUYtShvD-~agudTcv7K>k;;~zkzi~BzS zk?dt3U(+Ch*}9@LNy>2gW8P>Rq-}m2bLq;DtYp4fcJn=#zmrbXLiIU?Ro%O|1^cSX zMx0)XlYL+dp=fd0x05K-1dN6E-7q3SkP(x-TSz4nkPY~RhUmVb$cxcv&h_H-553iv z_RAs}tG}01ne?X68G7S1kSnpw`M5D6$`9cA*YvSe-gdmJeT-nNkgFj+2d&c=!>vIY zcJ1o-c6i^MXFR!|_G9$1MZ1SCfp+xoJ&G79gmX{>0@v%G4lOb8`a?&#KS3s3Th50V zBlH8g-wuWTVSU~0qGm-~z$k>>{`DdhBGiYgEg1=R)|J%`7B0o!r{1h48fH$pDhe9& zGb67Z00t@jsK|#Qd+#I1Fz}Z__A5YOAyLaumHqC3LiPreAxzOWq2NA$HW2b%?wr3A z1*c>uu0Ia_%+HiE^u3S)yu0rjd{NM$Oc+OEvMrB0Vx=6fLX);Oy|goo0?KeH&-jI6 zh31x3AO`XW*S65}{y>a%T!8ipJyFn<9IR@x@!2*Ew|$GWR(P)@P3F5*?w}h?{2HAxE$YN6cUA23Ob>~oJhSczdXbe9WaB)ajM$lv z;n^sq26fkN(tsrx?cyYFGW} z@^*2vH!1do`#AJDtlMjO?M(sUclGQ+{${j#nj_s%ya?*elf=z+pLNG6FVLr}tw zSEo`?LpC@`3pklhQ_Zt?lgOuTZRGsuNvLL5OM*h#=rwOYrxVOy<3;E2SCH-(fG9B< z3mfYv_$e!FTb^)-O6{7}S+Q-f;oi7c^K9sAN_8l-H#hrcM1i^zjj5HyS!BA$w33Qk z3in>mx|ZjX+HD8dDsKmQ-p8bao$vfT|8Z;rt8AXD_gl>7_ino0>f;N?Av>3?n9Idw zAbEQ9vQIxRxW%_pX|KO|zch?(X=<$S1$*3@?6B5VM#-9ztoZ6L2H?aTK_^Vg8PGzr zigO$OBItdgazjXM{H?=d$mctgDq^tS56b7E?9p}`^<_uX_!(d(kRVu>QI|JO`t$K$ zEX49W1LoJYW8GqYS8Dwnd_3Ma9Ctab=&FP=E)TroNjQCza5@22M9_U;)4moF_kvsr-v2U^6e4EXsk`Ad6+g&)mHKHB4g@G zeu|ldGWDWS<*FMlQlvnt`10bng5Oryy~B%2xnr07>nL&ZfeunN3)=}!9#SD5v2>W9 zpeFLwdDP$u>jQD`^&dJUZB}_=_C|0qA*t!xUP)K1yy$3p*@(Esg}*l_EHo zQan@QsE4fgM;f!~E{4_8U{DJ&hdwO__w*4}V{(*@48I@x4S?3?qR(p>5)E~|_uIZR zNP8EI@yB@;N{)r2`6T33M?ocslVW2I_cT#OE;E?FFIIF z;h*RbWcS?nfQFl!avc?dXDbLdb%z;+GM2mHp4T^x&crrLUCozmMYjE^Yg&_fV7WxS zcx+exOa)A!h);v@RuFl72_y*!Y+p1PxpFHjVbIE)vD9tUz3SwH@98_ zQhgh`_R*HOYuW8m2t=ke$1I)WE*BkI>S<|+%n-MR6D9SawZmA~qE@wmx05KhK-gvV0%US1a4O%N@THh^e zy&pqZC)06VR^nBS!~Y%p`08gfP`L=jty%WSp(jO3=mg|u`ehk!O3R4>2qZ9cfXNBK z4~j!v_&=f^tT5Nl3hHQ%=nG=b7sz5m|1?**edD%xmK1ASyN2)yOH8)`GCX~z$y?J1 zRHoioKt`ZrUL+&G)j%&uJ9OT8woKS6QFi57xK?I5d{Xo?{hL`+hytn6xmW&U=TC+# z&*RPY;ZB%dI2}Ckr{zD@f@&o44Wrgz?u;=tm3Q1-u+>!z>XNc+DIe=T^&$7XA{E^u zlF)RZW@Yht22@{|-~l;!Gu;+OFT|_hOiB{mA*B{_T&0qXi&S7Yp~x?Vrr;Y(CBFMb z0MCp3-8XS8XhK34Eaj(&jq=O^pL{M#gxJ_W|9y1wuenCSMaDu)CBMDaVHxVA-=lS< zBzC8O9B#~ASV1$p728OWS0!;6AtG9%6iSJ=J&TDxqa_me)MXP;^Mp8|laL#zgkg@O zsU`S8cZRAVRCED=uOQ7JqyY)yZM(v_ca7qbkAh_2y9*#0aGoa_Ki1OWZd}IJF8UNe z9g)reQ??%^KBZ_Um(35H80))^G|b-lV-o>_xaS1v&$lgza(=I2m2kfu{Oz=bcd@ix_Vy(e_+1X4YRKgmZ z4RmgLA^@Lz+yx4uE)-}bDfb`Rj;)T%QOpb7#=ZCERO}Y?LC)q&T@M*Ow>|QjK_-yu zHIddR5LQ|iuC+B@lRoUi5AMXJKkla7bkRxA4!=_|GjvgP`ViUc6BnnD?U+T>q7%zSj|Q&yH!|R(55@eWCHo6^>2np0`gb!R&F?>44s;UQ9)NNYJ}{2mCy|{E z`ylbx!G6n3EylG(QGxBIIMSNl*q)|^!hsHVN*I)ctDgdkJg@_!xKE+Ja}KFw6S8Pw z-8U5<&lk0<^#z;_EhmFs@ddU*H;_A58=5aunz32eB2}(^GhH??KNpcoCCvMb^2{X8 zzqGP*7dyQI>w=IfnrioxHz>~gB6y5DqwTfRW50+2N^-DrsN$GNsF&f5G%wt2FM*-P zAVi&s$8oPA+rBvs#5O9kLb{nRoq1_UmGbRZdFsGwk4c1m7N4Aewx zT&&L7g$QWd;Jup1He71U5x?$HNv6_FsZ#-jkOfA;QeL&4L0)T0Kl`<{Rl(3<9lyN-k5iPuINBEhZZe8lVg+?BsslN9Ffr6=77^pdbU6*8eakHhR=@?Zt_a zn4Y^dp->0aCVpH}(#YG-1(rsjD1m7Nf;qHl?n*e`mRD!^ zN1KY@EGKL#Obt*t&i89yeQU9w>G)}bzV-7ZnW9@*TND*f-a!{SDf^_7qiFthPr2=! z)!=k7CG-Oj$36J}X5{wVnvfZ`t4P#)vZmT`jhDN7oi>e@&vDN~&--KdPqnDPWooCX zZ5UMhmim;=u8EiYo09A0O0T4*n<8PlA!{1^bQSGzp@FLWZk9W$m?T!6`SzdRL-Tx7}f*Qx@iqt5< zkcO?wszRXHrrmLjc&F9n?a+9it(+g0c!Em0?Pf;MZw(?OUibPctnBMu)8FUH?RzN5 zC`9R@qKTnoT4NZ3w;O4%4yG@fkDBB=;q3k=rt*fv#YfUbRb~_{tE7=nvIQ|0zU%?D z#ZBYp^PTTc({rYDNOO~-R9g`#)}6#ey##RZ*}CrSyHS;;UKb~t&q_lkWAo5Cmm_$( zgEMw$g?EfqD1%646ue z9*lhyo%6pzrPqur%2@HCV+3d`DwUr?(9M`~NiGyQu9DvZlNM6D`d9Vge`_RhwE_Iy zm$eTPHYZ+%WM4YedA^}wDb&G(mh!RoEWW$AyFaLi-TdU^^CfX3Ym7Z_)T%j?4u{Ba zhL+EWRL!{oi7hx9s{}3$sWT27zDjP+`G{fiT@I^rE~r*s_-2oZIa@lO!X&C?BIt(D zz>H5fA0+Ogn6tNC(`T4ft#!9&@H7S%+p{pRTF~b5Id`7YP}XP9Ty05fQMNuF?JvyU zhzPg`CM85kVbgu4AeOOP$Py&SrpVJh&_XpBh|(Tl>w_03ev$HtVSR1%8_fFxCsCvaGMyD;TLFL?ztN=> zSXOR>i$d6qxMZx!g*xCcf83h(L8NDOl%8n_2l17KuD;JwxF}E907uAnMs#Gr0MH&_ zaA=6VaQ^_1_+!Pg-y2 zX{f3WCmzPZZ`HMQ&8ODC81)YHQ7Z>!Q9>5g0OYMWv6t@vSm3BZq7yn!I%KRF$ckg! zMT@-qd=AL<%q~fZU%^DhdFm99`t)EKciK4^`~8y1Fs^f*7_CPGkzsx5#)FCfg+c}> zd-p;q3|v8%r?1ugPZ4u-r}Z|}*+*7`3H0?aof~BTlJhgJs-N%Ij@IQ7@{GwqHboX@ z`Ydv{C&AgsZkp6KNJC6;d6Nm%JrBCuN{&9!2xeXm9cHTejJ99`NWCK;NdJUO0~F-F zB)Q@$+b(J*a%(A!BdW*o1SJcKwBUg+?!W}INGg({t+UQBBvvo#LiDyr^@5El`Q z{zA|1KT1W~cQU+%C{5zpClpVCp}?fqsgaci$M!bV^S0|&;m&KO~ZCF$rX6p0Y;<$uTA{|jgx6u zG!PM*DvTP&W{Ke5NIC~hl#dsngqI?+nNZ{%C5!g`zOudXic#U7M8_!i1HMn9=jpQl z;#haE)>ejgo-J(VO2X49^q$dEmC;vi{16#AjO-H14yWq(=BI5zj^<@{EoXi37a?E5 zvYS-w-%e040&O8Tj(wMmJ4%tbs=JvY|js zg@d7sfxSt@;hRgr1TKfuyjYI8`41TT>&cFO+;i58 zQ;GZJVa|Aku%m79$lCQm07r;K2&{wn&bL;fIDR@eg}ZX}gT&mQRE8FPIlY9lbQ*;G z{r$X6#TzjC){{>G!<|GQUQmU3%oq-ein!{yp%YA$XS3aek5S@Ge7p1qd&ch)PfIeR zM{oZx_TDnA%54i9ULXskL?s0Yi!SL7Mc8zAD$*?>T?&X&5(0~q?(PN=6zPUVcXu!1 zn`@t=d!N1EeXjS<_g&wQ^FuDYc-DI6GoLX>+~Xc&eAi^x;O__`Bf#|KTVk_oTsq=1 zq-kfqsLk2d10D1pw>np%yO>dSF0Ym82w}(REzEQM%ZiEZ8?xNHsi{stK{1myxEe4&rz z$!+o~!KT|_GP3vT@auYu5L?=H2cL6LpF+kMp*JY6s|#j=P|FFV^9a2i@oB9&PIQ~+ zHJ}e-|A?GSQMEE~3ZCqyU#{1S@~S({{MfIkROfa&%gjOvJ}{qk_-{rQdN9#Cg@lq{ zZb&W@XozN_Qbh=03>dn|w7429MybC?8)`sosc+PPnSvT;+y3nIPE)7YyHjjW#I^(O zFW36qmF5=Eh!a(~rS}#zw;TN^L7^Cbi_7xuwK~SPCNk5UMB|IXGEe^61JW05obm0= zx0Wp}TmS9=nX>)i`5S%&zcF6i#D0LKHSix_I_Sh?$qPEZ5HNW@mz_x{^P5YG?5(%& zie=_H`C4A~SB79&*MYf%lR*+O2l7~I0hvjjTJd4_s6k|oH%Q`W-U)IQNYPUBNNl^Y z1W0h8P``Bly=xH;Ix3&UTb`-TF;y&;AvLU0HXrrId)qUrJ^@OJqcNWyx}(f#Un{oU z)=oHlCvZI=hQ>wjW&rtmE#HsQbInUN@>2n1kJ29v9G-#!O3LUi%iCG@V$NLZ1aHU_ zyDi^KR->+G3SXFU^wK?$C=2ZP5%G$Hrs%V)bM2^yy;Q|WO6bn=@4W!;FeZxKyb8c8{_36I;WZ39D zZ5~pRDAc2uDbt)GjufQji0kbnro8+}63XA{XvfX1Kq?MGX|lHS%bBVYH4)HKG|zDLnIw~JY{F~-aI zm-|KX*qk&h0+&9g*=uS%xO2@c!9m`0sA|=yGnaWqg344AyPs_cL#bNSqXM9t#`&|l zho1GF*k(z2N?OYPFMV`8XDY!=`p*Wz9bZQGv@-!c>Yhu$A<3Oj;ebg!hF9p@iHuk41rInY*%Nmrj3()|*9pW`9m$zNu3~gGef!11m%0!Ec?as@ zJRNa^i_FlH0{V21B1*PLr|+xe7UTb|8GwH)p78Pc^;=zcab`mTUL`h>++pUdk*ddB zzaO~Za;OE+&(EA0o!21`=#QxHpM%nl@2NzmL8iB5`)vmwvs6l5M&Bd5cq=Hp+?+1y zM&H1W@`-975+Y4uc34b?8r1yG1ZM%dak-Z3#YS&Q;dWj;w^TIt_Ljc;?xXv>VfY3r zdlm2uA~=Qx{S8Lrr+c$E3ruGHh;B$lO}7T)AR9I^+@reF3Qm@+ouTa`ntSgG2;Me% zVP6R%a!o!2`0g!K-MnuwQPnlKeg1Ug3eznp)Rz-=Ea%?&r1tdQFs+E<4RRzh#M~C} zG;+UHd~UzFG~nsB3lYN_?~_%r*5^H_DdwPaEWa-s__kuZR5s(z^T&gz z8u_GkF~d6c`E@nqSK_93Wl?dOU6FX`=mW-ARC{3dBW1Uk3r~&d1NWlh_e%Th2;6D3aZtWDjju^>_5b>cWQ`ELOfuC%u;C~@CXV_^_A zBev?fu_zB3Q{QBM#w@zmdy4nF`;hgZiCWyQE?Z{HF-lzltC7u!;3DOIV-J7* z)_akK8(cC#+MeS)k6C7V_HbJLmK~PK7eU&F>yx9hN*C(bZL}nBMQ(}=-m~|Cq6(r- zfaYtI`IlL>x5>x_%$)HE)@Wnz%_(%>mwx_LzTxeS4nmEa55KvPkl*sfsg@?Q<;ta% zS6oW5RSADpCbNr~XqiVBCze=;;gV965kgyoBo)!ub^uQU`B;z zv4{7C_bv}GBby%{!b|KhcEwj@KNgZ0^bu3pDPH#3+zI$sqs76+IDk}Mi=T?{^nZE3 zjC5XFTwP~1dZUnp|G<&!Jp08vfx&Gmv?g@m^tF+melAOyX1`P{Nkgkx6FI$!5d?jy z9m!$PbK>v);PXj~8>4zqpY_dagHf07?#fPnv^Y&Vzs?=mMBx9?e_Kcjb+Vb8P4SiG3&fy1{Y zoX5AV!|WGV21p2=ykPfSU9Xe(lq2t<&%SX!SvI+}?WVKMK=gTq6onATfy)tuAA4Wh_BQr~KxAV9`_WY0skPTVaI>5nD_YON43WK7ap+9kYA@p2Vg6O5Lct)BB zLezV8!)!?lrxBJ0ATd4bg!4jnTo-@NIJ>s-CYUVc^I(w*(N9j-TcbaczeEk9zrFW- zMAs>BN=pXvkSmQJjm_ZvMDTsKvJF!OuG(W>vs*SeS2JVwN17&WxYx*p7Moj}P}Trr zGQ~Pr9ev1USvK(Ds7JH*^*!0ZX4@w_ZJJJFpY;S8H89AXManh|!)ZkIn25M~!J!|O zd6K_3-!aGPc|3Vv^b7jaz~HaQMvXMJkA(MTpWkbu#a{o6B-j({MR~lsZpP-c!E-To z^1hb`hDJh|?m;6jl*vP5c@~QkwFI-+dU1g}%yQ#;%#vF4#Fy5h3nzG+-`r6$4hg%l zr=XUDwD&I6JswbkUPs&6`Hj}y*=swwUhv;$xAB&~mx(?a>E{$s%tglT{2d%RIP1-pfh z65=$H2>9~!h?JsoZ;gI#ua+c~*IZ5(Z_`!n12v(}3f_Ie>D5q{B!V)9<|2x{Lkzbv zh_ub%I$l&(V1^Bh_U;h&{j&#x@$R#xIuMxwIu?3^eoBKg!!OGcUJmB5FcxdFmURWM zoWm25w?|))6ubnclY})qcUc7uT-L^$)u#F@v1&a8QuHgsl#}MSMB9xy{H{*Ao;`nN zhicFf7s5n-JkBCSN0Kpa)6obM?6>#ifMl2*3KVz;*9iGtv%9R4eLa=!A9{J3ob@Rc zm4dv-6~Rxs(sv^BDR;I10wr(PP7>werq{)-jR;?|O?c(&5eT`y>kl3+)`d`hLZ|gQ zrOihdfDge_qi3*vX2=_^&D z;{9Y=CJ5Wx?2g~2d}CruO@pndmmB>kC2q3VviiO13QbW4ato=NEqdp43)o%)eYS!G zi<-Hf7gHZ^))VIXu;lfiDQD(Yhz5_>xPFcQ>UfqxgZY=$q=L9?C9V-@V^9hO!{vG3 zZrTzFA;Hk@Qp8a-Dj^ozSKSYen?uFf(S#10%2slOd2~COX`6%fVwbB*6^Kdw=y`L$ zv%{71Ax`PUKAY%Mvy{n{#C=cRn!=o$szkG|FgLxTWW^dK)gs*t6t_5qyq?uFzYYDa z;y0`%Q3Hu-%caiJD^f&Bm3Ku~f^g~5ckBmz%G^VV8d`}_Yp#@crS84#EzYNQHX?I64d~oC74Wa+lj9n+*LJR7J>y;|*JTM=Jr!qpdy?k%e(S62M-hZZdA}4rB*T&D zaDr~FIM;E_HO(SNPhtP~DXzMbXnn(@Jkl3Jexc1e0?OvqtBIi>_Bu(r4Rb6cnSlh< zP8__BO~h@HJmwTsUODMw50j_w8D!7WIZQFEpo1S;UB?~@A9V8DmT(Q}7XK zW%B592Eo*)8bN0V742I+Y!9TEI}{;14zPAUvu&iXC1Q+8;;A0d7-*%8!iu!~me!KF z7$|&psP-Nf&xj}KlUD6jSDqtWfh|o>GC($amMTOniBKW#OAmbVn7q){Ui7M;oOpI# z#D;}lc#N8mXhmZr__0<@^kzv61qwL+R9?^nj5ieTRNv*05}c`Ppjew({y)T_+*Oj0i zSe%O=nGWakatIw1lx^;Hpo6;^*llxut!7Sxhsd<8KEfDVafNkFkAHQ!R7h4sJcK*? zSJJ>eNE5k~yFQ{ki; z%My21^cF0#mS5@ei63@7p4=vMXX@D1>~~?bbaRyNub1p$sy>5P6gd)^xcjv}ZA!Aj zCNPoI?B+M=_HCtn=GCwnv$&xtt5>KuDP}-heKD6u)YN*N${T|Eryr5Y-dG2!KV(q4 zRw^x|Y|9z>uu&)>%9|`hbC2$UOZ_lytypB11dLDlpikg%i`3Lq^BT8>xj}2(X)OrKNGH+U##tz(WE}9hYnrqg3=XtY=ZV zb-e1CG^&z!F!7Z)iV+k}aa(6;$f=6nSCuo3>u_SbO$G3`ln%gz`HUz9H zrsA3E{hi*PNHV1aj+O?rxm{J_{(7dS>})ufX!WI$`0_ny)iAr(Z;=@^&yX>#6m@J1QjeBF_faD`6=Y5Vve8xNMz zgids_+fFH4-k77BYwWl_JlSMn;`rcHAQy{-+ydGOcu{aH?~ry(zs z3$Xj^M*gRuyU>V07`L77+!6n^OMkl~*u&qDmnGbo|I=pvA1>RI^M+_lZL+Zi{l`lF z^N!c4!jPBok+=P)VE=WU3kg7Y>flB%N&e#<{`Iz0$jcn~f}Z}@^?&0>K{arx{PB(T zKZN$L8z{mDE?adV3HY`Cuu4=0wY(y&a&yhaj;MVnvTrRro!*hJB*_A{T&22fT&v55%iAQi6`rE*oW!{Oa!49_3_?YSZ~!EP8ijf6e^c_*q$ z)b)|V%246U(WUMLiw{IhC91h<)r7R819_V4{2N7IEI%++{HC>9V)VljC>$=sHXQ9r z>jbjQWKD2!p8az7aFyMB+UiAU?REp)^K6xd9~7usfnxQ&HxV^S?t6it*nFx2Zq3gR zDzM+!VL42K`K1+`74UIPn)sPLe!DrbXcMb9N}J>5R-p4zG1#Xc(B1P+_68lxK!$9ozUS%JU|~RW-CWH~ za)NvGOVVh*LB~Be$8rE5(le7XP#3K|QlN_+Wb#WGeu;~v2G|+0;kfc&BAkAI2XuWO z$Cnp)zQ5FEzpjp(BOXi|>(B5lJ$b+z$&3Cl-C{FaEftlwRk3LpA23MV~K# z>Zq`teL_r-qf=diZTl74Yz?NBAx@W*@@=LYK+#t}U|gCSwuh91jLVek(Z(H_lscTd zJiS9rd@ISIH^p+I{d%E(W5YUqqrTTgd0c}Pyn@+w*@S}KI0!s!Q>J&qa6VOxJQ&rL z#Aya9!v-su^y)^L>vo33S*XfW$?{Z!leNCofZW}5 zn7$O2xd&KA1|&k>d`ki4J}1U#v7v-Al@w=VB!LE)mhrwGuy2{G96-^gcD?K2d0s)> z2S^N2nq!5{^i;mEPJ}c(#j4*KnnO^AmD&6T1OA?np`XiV<(dK33|;bYzBV@;)Y15E z4(<`K-hKSyttznb%+(9GM>t+M3$CflazQ&lUob;r9a~Wc4q!8W9>agDwPXS`U^h_t za>aiBfh)}$RTS$wU3Ru8)CEhLrT!os`_(3x)Z{c5NYf@)kR0kOEE~t==##M{R*mJI zeMf94=e@L$ce*hyU|fZ!NtR%Go3(+{S8YrlLA2K%dhe-!jQJOGuk+oC0Xcrcm<2$s zbnN1wux&yq(ENsq&-(Mue`s2+Dxl$T<+`zcuGa^bVdn^L0|x@P1-qsa@isOMgTlGV zgK|AmSe7vj!!*o-YX_9{%IEM#VKk}&ExNKAuQhD}tu)LF)8Zehb3DyXvdi!kq4bu*H>I6DM2;c!L)nCDMT@N1d0 zkHAq#N9!^FV|9;MT@OqV2LtlDRFWv^E#VE#j`P9XHQT+zG_`FxlCrQzDwHo`H?KPB$h@r*11JEk;+lJ~pYj$A6OnGYyRZC&a~vH@F_4CWYR z_YN^>mb9w;eljy)x~u(f@PtgkWY?%?7Uqj!QH@?#Y2L~_Ea0_1+o#YA*rwz(kCaUk zs`s9~IG(nVj%F^O58>~2nsPA_=0&0dzqaJ}-)N1H`%-sJL-6PF6#7xW1mIOZ`#_`# zPE`KWfE#`Vas%dxvRq?e8H~E5d=6P2pi`Gq>n#b5I4&z+Np?){`m0OC5df7&!3(z$ zbUVUXQpGLvxrR|Q4MuNfBYP7ySJ}!Jpc=%Y6)ttfnLH2=D&lio8-)_<%#;*cjL+gJcMM-MEe>rX_Xc2RF-$VfXKl4UVgi&-QZrG02DmX z_l9oZ^>5@?PL)(x!N;EmkY`B#_E&39r67(xdmqU~xqj}XPxx(T&|}1MZ{a($Y3htD z_39^W>*6HOv+r_3r!Osl$=hHAKZ}8_n+*Pd-T@kZF>6=9G8#XX2)S!!zts612sMsT zHJIT&25cS$TI<=-rUfn;R}kk5s-G|A519!8GShEolK*pMP3ZW&+%*UJ1z3diRo*JV zW?<_c0}b#}IYXux7^H4FzSXqRRj>_42vGcN35a6F>^%bPW~BP-0Gh`uciJ3(6g&_L z4CELX5WZ|48YPBX1eEzG5u=7dz};8xHi07#9WF#cT7<73h)vEf3c#r9W^`QA1(?9b zWNqatLjQ1mq|&~dm&WN7=a*9YwL$&(zPp}rL3*R0WloM2 z=tLvAt~TIVZa!2(ubNXeYmRQWGt-!Z z>m%i2jX9};EZT5^E*#okrk4bis|lXqK^Prtrpj%UB6WR_A<$Qk+@e1%5U$s_Wy=kR z#4HVQS-`c+&5hWNJBz?^8Xd2+q10o%__?J&rHe`d9r?0-5=4l8Jxe&z?_P9yidvq= zteR@39Qnw@Ie-*yG+2})#TfL7v;w}x^^%lrf5EHs{R*c|E%o(mpaqykjzD&NbZsbC zSH$w_;aaP432uEIMS%W9fGy3sKEma&B0o37Sqf`|A80hF?f~68A2CJgwCIqe**{!uXdT~$6U#!cDgVpP(wcs60F8RlWPZ}HI*?B^^yWh zPxozk03@c(^0h0Sgg@Md3&Yf$2xh)D> zKTwX+Kfe6-OU3&HYl38+9dmEF!>UpoyGe*@mO^vQ>uu{=pn}>uTPpro;J@}7#Ku6} zPj$u6e;P>?G^wWsz^pm}4kR>p3iJodw-_m?00ss9%gV3!@#}Du(1}3uEVqbX`Th9_ zsTJs$<*FBQK^uW{sfzwe?AK}f^$b+_;K^fYALIT_-~HKx6PdaW;?p?YXX1aX@8`XL zeHGX{wp-v01l}I_^Jjl8=$Cvg1OrW4H>UcM;Lo4^+xPunE)9WM`5gigGLaM$Rr&w% zGXJ-ty?|LxJ7sG(`|+!=1c>RTrO>)8Y$rM#9#rd&dvQo5An7q*LHfXxBl zqN3~KMS*I8(pTUtTJUdGMGOIuW8hg@g7svLBbUqGLYf($!-@g2ds=@{izgCw1m4gc znF`H(t>GHkIBy|#~!yka6_93s+>29KUT=!U%4%(d-W;|#Jhqd z91B}+xA*VjpJ&i;qhc@hRDx-Z51A~F;#n*KEmxLQZ4?jMe+J_7;5+;7K9US7Sq7l$ zIW@t(gAUqe#BXqTJguFp#{aO3%Vf+H=1P=efXktENZMXc3zLh2Yv+RQH`e z_%Dt{lRq)-A!Kx>`Sn$-JuHgAJiu=DJZIi4RrN>P#c_rvA;kfS+lmeDbj zBvq;i&=u1U#N8cE<7PC7;}do4AeIgYs=+fwLyG@6hkv-F;J3Y}RE5_JfKOLZ8-P=s z4KfXYP~O$ezwMq20M2j$l%j_rw-FydKt>O*VT^y z{UQS&$BkYgv(ICm*MOJ&VIwv(>Bc9!xj?US_;%HUlY}3MI?$#>_dU$oG_NZv3-@b` z$;lZ1==k|4;nUiq6g|Dc+v<<&Mf)IZtkeXa^6Z1JS>=?gg#~b9ceDk^(3_ARJ!Rch zgGc!SL+PP0E-6P*J-m{oXd*4@eD~?;sp*=Ec8x=}N8_1Wu6|(yr|D>uR;9HvVC^J% zUB-6B3bqrm=xuze*WB#NvrBEO*k`UC1>1Nxnvi<~G)E83{uJMTgMY&SZdn?uIvTB4(%^wW`@zBp$$(jo zw}A+945Yu7%^A6@#yfBD%s_Ghs8|$l+XG@si>r%mugT=Kz|HM2+a0sBgVm#EjBR*} zAGTFe2x3&!>+}N%=V8Yn6fJqA&s1#Fh!_T~+UzYxlRuZs+{Me`lzj3ZV)$oYJy`&2 z!4a}SIihEXCv;*^qz@oyqsl2KZSbOE!HepQd43IDXAV_E68mIc0$yQdb@CLC*z|>B zs!12jNL|mxuO89OZ&zCL-0EmzfVpZ0b$$GBCUW4d#5pLD;o>N^>Jiv4qdN(w-)y|P zJOU#y=3$sYa`;n6Q}u4}!;xtNPzo0tOnMkZH$xzI);+wau44vcRy`Z>I3C00*3mc6 zgT6$^qj*6+zHPNWoR4kX!vW!1i#6E*@4F0~b@ctV!@B+M+Tk>_0fWKy!g^yca-^K= zwe`7s#|Ts9ggM+wo%QA?Gsp%&yk2qEwFS8dX%xEBtL2&2-&O-!wiMs>;Cfp+mNycs z=Q8ajKbpCQhbH>nAVW+(n3Qt^W^r|E{c78*@dZdEz~bs&Ep{A@Ewfu9!@I8OD{D}V z^0FwVv|9*XP`#ve?A8V2bW)v*xeKE9RgL%3B^%%j442c-fBMS$&zhkl90XOZQ_k!8 zl1}5fZPgL9lXaxWGriA2%fJ9aE=|_U-lsQim|vn@ zGjvsv24LDWE3~+U?k;42!;RY47GxE0ffQa9e+<=*X4b{RQ7Oa^_n*Yh$@4N)0Uoeh7Kt3mimaYvst_QNv$KJCepHSO}7lfw&=% z{J|sQ`qYU^t{M~n+DdAEH<9B8Xl2dGDY_DYDmdR(ZwVkd$2aJB4L__KR;h)@32b>+ zk{hd*P?jITs^dPH)>w~~7!4Oaf9ke zBev{|r4j9PsVK314>*mlleFd6_k^BB>-0@&BFa43#>1Y7E$!qb^#ndg8O}Hmt=~x$ zSOL=MH2OIp#+=cN@`ReK{3ho}rZJI+>t1#yeixawmHGJYs9_E9H~D$7fwv6m`Sdqs zfIUdWz6k)h5ta_w)Fy2n+1Rs>7JL18%9}Zt#QGav=(>xd?ZGhipo}VDA!~29f9vw1 zcmOjA9nRkb&}2m{yKxO98n3}ze>y5l_Vq@wmnTLKC5ET&VdZ#7!|9pD75mDR6Jqmd zr17W>Pxw5PJjzsvE&hhU3KhISlU=##Xun4o&%8@E{@{~E$72Dezax6TUc^GJNG!JZ zYOR>b(JI+`jr3fc`q`%_`D#xR1^56EkmP8Ok!fEcXBS_6j`TE?hy(alX(h@M- zMb;8`XFZR2_k+YlEaNGoOqX_A#FTy2(Hd0|CUdQU1x~-?xHvs&5?vG7!%;BV3DDL& z!dP*@%UrI9rn+u-3GHgY@e60u`8x`bErdZ;Zpv`RGp~Bty>OE_?JMBFDDBbR`HrV@ zlXhY-aj71$<%aquRQT+h9RKEE8db_t7Y788YMM`%$H1tSbuXf#g9ilXuG{s(Zye5s zN8W){jV!r&9I~afScFgJ_;|U+1>^8>Ug^fT82%d}LbYo$2&?JtgvrX9a{;UuIsWkt z?3uegArw~En8^)t>=u;co@#}^>I9Nm%%`d z^5bc*o^GD`&a~O{zoa7m^xtHG>ygzU`98={SknO%HRvy9f>OxzVd`54*qPCKq!#(`GEDSx>v{>L z;8gaW4a2Lttr~+mSAr@f2t&NoeMkks)Zi99T#~YsIg%nC*i7+&I%df|>1@dQ8~k!M zKpE*ETWdT=Vf9eYv(H>G#t*>t`gVhNLEfHer61+m#%{X=`g$OGlb-YQpoEAMu4sAC zakw}**LNfr7YjK?j-dE|aVqMtEC*4FK(*lgzE0iD zyko1XKt4|G*IU)gqaOmtdF--5mTZ`%@2$b{R(or(9KVe0JT4`dKwsK)8ftS;)g5eX zZ`~+UqU{O$2n#ba-pylclMlC>Ig?sYilF<;+Moy3Iqk@W!Zq?4c|MA9gz19?;S`G`iW}Jdm9v_x2GuK0a>amz^s9y(87x1V<;oj2Bm`m!V z0fmjb#yjxi6@)F|PbXikqQ1epdFHUiyF426xCfDR=k=E^OYv(4=Dx4w(kk>FnscJE z#slpn5d}8)dEl8g)5+OARjVZae+M{zMj8!R$U_M%@J5K}>o!-A*&5)QbQmzuDRYwT zNvz)(hFfE|<p_~ak-T)fer0;mpa%wqOh8UG;Z&HV4DzdYg zHxeR{Sf{#IJ{$ zKxrfNKzd4}U*H3gmu7NX6tzOK3<`S^IFwFTjh99vy2qJ@Wo=RVl{GolM3*;4Q$vHx zuHE2il2y`xY=D^{k~xQ&O|ht^eQD!r=HWn;JzbC2%xoGoS#6gx<%jB7iW5K*Hj<1S z*PGL9d~i_g#q(7_Unq~WsiC8*x|1jY=a}nj&%z}V|4jK$5k#^MQh~)Z6sOrR8HK+m zgD98!lJlPziihb>Bb`On+b9_h*-k0Eb-PDb9 z9v-~}RYsc=MJ=cXsS=?T*eoaeZuZ&cu&$WLUx2eBU6g1F*+{`=DN;-oht417mwdUg zO>{0dGysASWOnWM?E+5!V7wus5V9N>WErgo;c4m-r6&L?F8V!P2O) zzX^N9$#Sy2TR6^K`w-(($>c0n0S-Ce;8xwbobo1XQpk4Sm#w;e<|}ri;23V30>^QaBm>gJNHK_vD9=zD5I^0b0$XKYPXis1?1!iZc5p$9 zqj=Qvn3Qq^y?TMAerE!)`xgf0##tM05UaX5Z9Ja5SgM8v4BVcEA(rd&)&c&| zJTCX>brRc(o<0mPx-Rqa9c-j?~v6LGP*hiNbSD2my zZ~pl>x!fGhx@Iu$1NyQC0UMvx^*zD1B`}bh1jDG#W~5Nx1~8@GC0u?KOP&Xr_3Le$ zeKqC5GT@#XK={4x8&E6ImIbw z`zNfD&w=V|JntVbpJa&96RezYjXPW$VlW%kG&wAf)^mSMLWJvGAD5NwIAPb0KA)?W zZ(dk`DXxIeMDj6%1`g4vF?9t=?A+PNwy-NxtaYROJRH2{-p zY9~DrRmgw|loNF{s4PGB22Wr{ zqShKzD;PwYuXQB}v&6`Cu}-(%d(D>@==3T03R~yl>^axy(>AKrB8jRUB4;eiCF9_N~c9S@u1><{V#=k15 z-#uHGtW^-r^v5NG`Rbn~M*3n%Md3FWK(R0La2=Jl^^U;EL9~5qkdjv`^z?{Bd?f~H z>~VuCR|>MzD#z8m<>QoaasS^@yd%p2K8^*idRZ7(dEsr&h)5a`Xwb)+i=C<{p|C|K%TCkc@2)U13`T zRxc2IR?5I4q@X~DuH%DdQbXHx*t{Q2UuS!Lbj44_7TuXKJ{fQ zCXz(P_kQ}Hwdz7Sh{Suhlsaeir$^eMbJg7<(daN@~p8P+v`>9Tu- zN|(ExxprY*t1anM-XNuDp?{d6_2{lYv zr7LgPZG!?WU5X8ofg=;U_k2!UJ9@114!bX@own5w)owy5!)6uW4}ghn!_ahhV`*@q zW1eo= z13hcfL`Ir?MzrGukISSnaIV8@WC$SxGG_%bd;HcL8VH~dFDsLKuY&Q*%fK)$+URA# zA>$&6u)-}uvOx1q`db5`sMc8HoYJFr9S{1D_@M^U>pblJZyNd*z;ZP--|7HbDz+2t zPTJDE%2V;HoQJ3k+2IXd>B;^Li)mU)0Bd**&3*Neh*>8_<7gz1`c7p9k{*$PXJ0&# z!u+&3RkPG2)>l7AGkxj4H2-%mpcU2fwKy#jPuf2D8dS^ad({sDAkY#}^w>EaH3!pX za$wcx)O`oDQStl|b-< z-L6Ux|Jyx9s__A>W6Oz-?CqaF{MV0IPJp@ruC0rn;eUKazRHD%o6`QJG_ewZucDHh+6P&B9cAg$%Aw&=$`oEF2QfRSZ{q<{k=6V2p<6iue> z-q`$mM9I7Zm3p({}k&i8r?*nL%oWo>P?xMOe|I0mJ= zfdr*T88VafsPy(Hm_3T1wg4cIXFvkwqZrgHz<|F_BvSn&n&tH|jJNt% zmOg&b{oa7PJ)~lb%;w}_E53&<^4c$re*5^qYQKxS@&j{CR@R5_wWsc%DUdZ0jxR}k zUSJ~K_lEO5X<-RD$S0KB5r0xt zzbmhu0FhWs?{d?=7Q*YaJZW0b&FRJcVx&MdOu3N9*(exayeCnyU%3ycRWR6RP^XY- zk(iZMDb@wa@s@@%&%&NOs-FtiyX=f*M-m{}3CF)a($A{Acg?`2;WWeT2ZF`xR9ffL zD?Ub5*+P{s_BF4FDipD4lM7lV0A;vZhOZ7#Vl%XeLBsQSx4;w`v-|-}tga@NsdqbeLb=m;9r@5p&*o~MVR~O6rmviO=&B1OB_WKS zl#l;PRr2BSVZ((@CWyOfngP>0orXaQVhL!6TsBhz$|7vh(-Ze0pFH&+6aDh8{*|rq zDH4gj;Z2u%W_tqC$J-5Z~fN-@!U5%eBl)MN(n)4_vTuwgLs64Wp3xZZ?|qv4e}uk1qU zIy`&Z)<^~fh2a8Xp# zEGw0cBT~XjiodZG!vaNO@x09*oKqss{G%F-2<6PF0azxPVZ%gwvkXjC2UT)i6R*Fl zjTBNQ4ju~cG+o<5kbqQ?y)0u+Agr+Atb;K8#MoSAe}7XZRWdBEEKrwJmXVL898#MO6vgFwT~8MQ6j%b(7^LF zOD9}8UV&^or_~$tw(JT&mL^5fL7?+q0tE0gT_Jr|uWJ-Hr(>4cMFqmj3=nt`)N=h& z_`)h#2cTk&zY!GtjKVlACXP6*#s>jvUOBq05=72F9Gk5vbt)gv)5lSGuKH~NkhS?i zRY@L5F7^#+a=|qXmRh|*S74a0Kn@{o=#KV~x%htA(;IfBr%&nuS+;A8HWU>0un~4< zNp=C(Y!n6KuELCSf9KvgIR6uss|%IpL-dt6mPsU$M-S_EpWcxi^{-%)$OU!LwQcBg{uR$pJi(GpewgQwfh?P zx=_!9LFygk+)$!$lH`5!!7RnC6QR|#2w%zfuQtr}&Eg!~E5L#^)T$)PWo&P*#B`MTn^zz-+gkzs+$!f@uHg(g-K7B0Y|(vy%!wg0 z%h}&$bw8xg#p@?z7B*hi@asD!g6dsIrG4YubpwyH*C#-s&EzS-eS*^rpUKwv_k6Vs zDK%}luxTs=%;}_(irDU<=U@D*_n$4-6o9M&Z!S?M2pl$vi5=MMO)THdPn&eOA#tPx z<+J>Yl>H1q64(-2$UM}Yly=Y+2IW{2^4hCAY6}qU|Lj9_-^(9AMBtyNuZys8L(378#KQSa?L5p;Qkq zUo=obvjwH&%=!B5Szc|sKd>m@xEd=dXJL)5U*-#}#Fe;mDK&gSwDuGhBsMxwtR|+e zrzK`bnoLfs)XE_$fGxLnc5bk3Ox!Nh8&Zh&OB`{qI_R1)EyGkJod5zOzE37#c)Vl=6cq;G3wDae<5xHpGzsX;M7A;@cJ z$=SS)A0fSi;yphsW01NDN_(Q&mFjzqkUqyi0V<4jmyRT*1(Ogx*Y??duC1aU9#&Zv zs~Ge;J&yX#XMT_AWfXlrnm?rtD+1LBHI6xuXV9BcU?5UPT+hYHd}Ea_HsORRKSvUl zVL>@hgX)B>@f9v?2=;jP6uz%ZffX2w$#Sxot9qG{ z*3~v&yFD6f*I~*uj^J)DD`8!BuN*WIaKT?GScv+)!V=g7BaB7w=va2 zWj+(tbyh8r)&1Ok6}1|@mAk!mY3nf|n&gP_}XmIT*F4 zBSNVHbO$)&kXeq4H*)XhU2c_I3RQ$&5*DfK!9CWpGizq7o!cz8?s$$payduTof_(7 z)J!oLB(FynEK7|y_SqDy>ZMr3gwz8j&5wkhn#$G0^yK&91&{c+9rJNA0m-1&UVAxv zIMc$XfY(!qTpCO0B`IY8I5xb>#MoZ&2)+{PW4WyeYouLQhDa^PBtCGE@4rwRvGFSG zdz@#e(#@CX-m&C-urF3yw2^GKumQRLfyc>i zbp>`Eja#WgRO#zsOPC|C27W-#y0iVwv>h$!t}lg3LVxq{)XC^S&xBpMX7s&s&{?lZ z_efpO`cxSGu4RPD3#Y<*a$Ix8b0Z1va1kCF-bM)~ErUW=NTcr-pSlA}WI}-W4BRW?Qok>N-N^);b$2ukCQ9vn{ zr{_@+ean*758v-IM!1W7BQPQ567(bT}1j?xLtpG+w zFQ(G<&h|Y+)sEjDR!6q&!*~_e6jVz6-qfZ+0K_a|l^*H_u8@u9RHr;4NII`*g*K@? z5c9j&k%^`8MUK7~RCF#+xDui%`{cH}#vkk5v_KlV!yK z3rj&RYC5t}T+`!QiCpm#glDujm!_L;EGu%>sF1P7s~DugNM@ff1goQjV=b1+GdG;f zB{%8Mt0d>m->>N+jg|y`D->|H<@1+88H%0HjUi*qk(S@>whmN-FH|Ka-B6|-CQq8_ zk_`h{4|gF4!LE`Fx|XqU z=q)4si1kR&blvunpU>Z>Rs2RSd$66xGwHDWj*EF${yG9Xxn3ZlyzQz3%j>fH{duyycUqT z56{wK7Al$vNFc@ZHgfA3z1iM4O*Ev`Crp`k{N>9ro9_0P@6*x_lf%VX zf>1<(sdY!_K(>2TQ*1f25yMPyj3N|9qq`?dwFSZ=QQ4K913-i$;OG~8+N0)mv92GX zC$u-xw{o!sDuV1#;#aCO-DzhEnp96Hh`aU6^nGZcQ!kez@*E45SoK(<@7lHA@{GjZ zTUmrY(oKz8-l?lO4!+CVFUY>Oco#b4-ftfP;~A_@GvU&;@K6$2D{iN-U(WP@w(aOy zQ)NwWFPrNfk1AKwvwoKDRw$1}n$wn;IDN2D0@UbI^raV?O*uiQb78({6V`Ebx)-v*>}9Z2FR}-Dr8(U z$eB&93_K(HqBd7pq5lcw>~w%M=8LMOO*r*2KXNK}-B(20IWO=Ay!8`nF#NRD$| zWo7_b*h&5IoK3YN zlZK@l1$v~MwNzC(R{POhGUTDhzyb&D@>|Aq(p!#7yOs0V@4h=)KSKQG*Gx}v^gSsP zD=!D#?BMQBv&5#`P{un8@jjLxuP+?ANmc$I_TDn8%5Uo%-hea;h`^>rBqcT=(jlct zNq0+kcS#CcP#P(vyFp6Wv~)L$fLpq|pT+;2bKmDV=YHSw`5o{5!7&&N2YX-Fnrp2& z=P%~oa->)4*;$s}gpKlD1$4^?#n_DBpui2u=7G==kJ6>v3*1HDpH=nd9&<55*X?r; zrpj!`Bk?u#T-B5VYg-bT5M|_VN3wG_T)stM;5-l-=520UQT5PAUjj&>0&hMOO1bU= zce`igab5%Ug~`K-qaOx0Stt3c`&li^lPfztg;z!1mVC_99-z{x`z*^BP-Yq7BovxR zwKe1lpn!_9qxDam7Q+uuVmfZ!?^C_Ka$m!wYWmxF60$tm2JMCM*S%8;bBIgHb~0S6 zZO|(+d5n4HMaLu!n3RS!T6v zc5kWkn_Q-8;bg5kna0jUnF=p*@O!t*zzId*vW< z3n`;1IXHH!1DaPKOT}WWbeX5KP~SVClv;JI-ZkYZBherz`6TbPtX4yg;PCmE z(&>9oQGGpw51FW8Ku9eh)O&Q%#(nkrOE!nc5m6!JCHnK(1Te38N9OE!1D{lPRfpKC zNGrsZB}oSSG1DUTsJ9RtoWggh<&i@{JLk55%JPP>U3CD((hprk6^o>#=MS!MW)0@0 zz{G@G;jZG`j>@ySwUu`pW<(HKwa+<7kZd(q<8#ZO*M>Gvkg!3I(O-`6E^+JG6|Nmh z*Z$OwCeh5ft>8sym1JMmgaF85yLpS`tB667Y{*(Oa}V!=&zLXKW6EFq-7SMO{Q1(E z%|w~Ghd$?1E!RlYHzS{%{Cw&*(7GI3`Oy&*#p=_IeBE}yJ<5y1U`3x@#pr@xdzwQ3 ztJSt;V`dH6l_xn{HQrDW1G`!ulWq`;kjU%~?v@HVBEl)!bKyzm!_GS+q8`B<6=Y)nQZ{M710j@#~^*`tCnZ z-Q`DipOvD{7Y4@Kk&Biz`03F*4&jwC&StE8ZT^+ij38h5cb5zqTr8Iwd|JSy%B+D# zItfW15M6HtJ+042$-T(5(t0A6KdbC0!@;nMj{eOs^I>C5^IHDwm=%u734E8AemOxY z&d95@?)rQ~uSCO_bdu2@uh4B9Xgs$u8C|cgIJKX=es1<-Dsv?%Lu-gqVBzpG-iln* zwl1XWI#Fs+r=h}uNmOk>v=q(TK zL^9~%y2xYk@)TKKdM0eACl#$UTcn@Kl(KO=6ymIA_djKQD&gFpoa!M zpv_+V;wTK4y_%{}Dl6Ao6;Turi{q+-zN)&K{nnZ%HcQ*gtKA@E!Ldf-vQ`q!P-L3$ zELe5^B#4LtjrigFZAWED8OMHLl;(Sd{t9C zs)yM&2e>T7`Q2I`R3m-{!=?5&;4wCugq3i9)E&e zeE?q%&4rq|g*fQfW?k~EwmsZPv2ws?6c`c@{1EG^qDwb z^emtKZo`I)s22ASYrVB53OHz-KZkN^^n_BKBxrH*+csVq~#Xpyqm(3|G(JZkXBED#d* zJNSaxz=1?M4Hahu8M31G{tc3Gj@%F&g{-|teA`eg`;2pE&#M#pRm+Pbu82>Gl zb*nj{4hX3Y_VvAdPn8^9420^2dX2s7%>f5>wsu+bR`y1iVuPr4qnd=u^C$Fr9BLcA zQx6Wta@W_%Ze=FytC^7a?GORRL$0WF*TXiM!?Pz7RSF(d0AWWeO_i+fw;dELOj!*| z-G!z33*aw*>bY0OtH!2rLrEcWLi}cwlfd^GHizO$%v-$?a>Hw#$cCTUUfYvSps%^s zmtmefPZW7EPx|xT`M=UzzDs}Z2fO)O0o9L(#IFh=V)FRwIz%(sb#H@KFGGm4<5VI2 zD-xh>;iKAGR?DNeSiQdwI-!kg#7RoKvgki?jG1y~Nem7oLNp4c9whpFmIES+qYy4hD7$%DLuKzubg|S;3i@inO)PYd_sw zN1zGoec|TNR?sQ80=;J3 z=!mV8ZvSfOw;6SO-N^>h)kUZddWz#}@?ylJ=O$t(lMaiGe~#v;L?$DhhnUuu{o7~; zV%Igtj`I^zS|+W$edNDdAPUR9wF&|6j<(>lWwne*Ngt#Cy+k)~R8B3|nIP;_cDjCK zMKp*|8JsuA>A%Eg{2_RFCGf+%{i2$$+r;B+@fw7d&%lcbESwgx2l@s^SA~Rm_NXl1 zOJ`5LqK0MfJIZf{B<7qQ#)Rl&DGivQ54Q1qzq}G9FMoAZOr-Co3+bP7QJiwgOjrz( ztj7vi)6O-cbd_73VVQp=#@Eu^Gr+FbQ1`HqhSYug!akx?kLb!rq@3(-z*id(fIlj`Y>S_3IK3*Z%m!c2|yvmcL$$ ziQ7(4K+kT>ZVX0ezLK40%|uk9j=pbeyZ<(><9>|nODrbj{g_A0Uv3WY`c1cI4w_F& z8c)9Uac2x|U;I2sPv$<5OJ8s|etSdAj`z87H8ZjexMV@;Xyb~oVP1Rung`OpIr z)tlml`rQqK8v!urf?^Rg>amFw_>6{x-wTQUxb4V?Iu8l+0yT`FZ|(ueLG9}RWw;&q zWss5p)2s4HZR<`$s~jX~{vYU!S!D*XB6tnT-Qbeq-IXc-n!<5ZN&x=A}3mxsv13ueSo$IoUB#FKW_^-t|4A2NXr8;z(p=>}(xd z?ewF5Ku}_?)6X~*^uL%}Fiw$}8%r#j7<%kqa-7UuI#AnP(<>H%pP}ZfS~PS4#(5I~ zhq1O@Fps43ILV0Eb_&q+s6ToObcHky{rlo$~~nL<>K= z1i>4zwvSz(sT%?oRk0g zSVkL=jd4vnkM7in6!j{Uc=t`EP@TkIU3|Us_#q1ROEJ{@9|HdN<7XvQB0O~zypaG> zKlnZsZyNL~tgs)}j%Ne_=ZKR@E*v9C@q96% zj^PZ7j!_9au%R6Q{ud%eqV>2KtnQkVJeu>+-OfaoW#en_GjHxS$xR7}gk}+a<>Pia z;dVbYN~5=n9$@?21L_dpGK+m(KYuV1OhOCd4S1LBWag=aAs<;rsx`!BXs~3V$mXLG z`w-IvErttZR+-Fe3k^skICa{ApBhOYfoVZ+n&+S7MF3~wP}r0|*K}w__qJ=zkNgGe zrgRPlkbNJDQmGC61)qf2oXePeJMf<(05&zXOmB|vj3N>NEWwZp_?}80*?4rTrIo!b zMgXhcK{lpUrr>=JmYFs^0V)p8X(ys0O8BzZ7@shNZ1Wkw(qLd5$q5+h z9ass8u@n2;^#Q&}y0{Obz~{W+591cfmbjLUEcGn2IWxR)2pk9OsXqHXMnG_f11&pK z(3WwY$#F^C@GJ6__D}HN4{*cEx&RGfp~*LaIcm1i-r8zVX_JrFAddg}%jTIRcD zT|+&$dt?&D&k!*wdfJNLW-fX$^XZz}YxN6X&)aJ=5CoJP&2fYKce1rj(u4xWuM^SB z$3wXWjha;43hbA>^6r#>qR zL>I;Ph&=6k5zBK<{3pJO+{=V>1V5a*Sp-J|tu-JfQm7d6`-THNQ+Tqh6_VHaN$jKD z5g|Y>ZOgh$h6*i0B{0++soN-RJl>CX2o30p5bHqf<5cMLPMx6z(S*9I2UMVuF#I!9uHqkO_dbpZw5A1+2fq)OH&+laI&hE(A)raFl08cEEU5^GnvwoHfwF&&zp zDHerr9-AC0MxA#RDzB52s-QxBv9565iga!7TXj7)JLnH2L1^1XtIXKfMq3?u7LS@5 zL)rvTUujEq;AnO|R4Yx}*Cf`zA1Y9R3g1;pk;*_opO6}k9wg(%sIw`b5bEW9vMM}u z9%3x=1-h-c>C(iDsPq((Yw;vNmC@A|Zd&lWII_wj48{)QnwLRgt+CGj$Q66SfB0ft zLK3E%cL#P(#_$mF9$WU%vwk_bBl0*(M9^Jr`K6!Ya%SN>Bbnbz&6N;oa;=Z2qp}VZZ2x8456!DoD@$zw~TdmbnXX=C!)HGSE ze=?}a#iSe&o@URX(&z9&qKJ{)(I5{U1}A~KB>6^iVmspQMI{eId-iQ{IK#`??me-| zO*Z@FAsQ;T-3|%m3q-*rsq?Zl>JyN})#S8>hC<`hfvLdvd+m6k2bG#JaB88vWHy2n z8FRQ#+D!~JacsmO|_38ajs~P%q zFy~ew6+OBR*M2k-7CJ2UW0|Jvw;*#sP0A4PCRJp`hgvLh0fIu8?aLmOSs``HVd~%P z6DYIzv-c&{FWY_rW4kD1a%IF`O~OYJ{OBDAb9zi$c2~5$RAQVCj+&~ixT^hw{T7v( z&-%27w>-9QwTbd4xh@(tiY13+!E+f%(ULov^R0vue71LsBw)|l<89vx(g%D@ueN1y z4cKqx?$KF?6#0c?UiFCK-kyR-y^ytTHThACBTp<*KtXn!KR?PE7Cp;okeVAT?5X@d zV&!@H_)xLgRU1P0CfMwpW)`Y$@W^h&57w0#ow;3gmpSTLVEjxqH}@c)$>zmw*k`Hv zT@~w%8K~H?fwphg0l~H94pU-q`}&*ofdhi9m?GXunUisCl&+nE{?{uOQ~B=W66bz* z3T_VF;W-u=o(#TRz8JRW;L6~h>|M}ao_6wlBzNvH{kj$;v^{m` z4q6a8b~t~ss7os3hxWX>XU4k{rS&~^1rbsD8x~~i7FW> zh+Le!Nk(ZZvmefXw3a^DFN|4HdQx|pK^dua+oz+USmx?MaT)=R_!w_GWYmY~HF$^w zuM$K!HyvxCRb{afd|8{uE<)$4S<44={AjEpvQ&#g^l+^>6G{wiJo|pGA#-;|QJ+U$ zw0KLJma05`8C!6^cHAs2yCirz`6a$%6n8XJVrou8hPU#)%=k)KXzFs?WXw1%UL9Ys z$zX!GL$flrE-W{-C|Qez^|3|0O5f_grV8l_c$(2ebzi!q;}0zNZswIt0KJO z(7t*s8@s!MVHDxzXNhy6m;tRgIR7Y!A{dumCH*%jIP8`c2BC2beMpzBD`j`FS}&4R6UB1THvE#5CO zlkLvlElapD8`XLOccJ1$3&JlZcrTE=vWp;qw^oi2b9Fo+6XrBV>M-Z zAG>yecES3Mr&%c8TpZNV53C7#KFt@gjS*A)6y@?z2?& zb;CFM1q4M7<1~2j;UA!h*7YpQkFN=|G|whV=~!oJrja@_e-_=W`DGn9b4Ae9Q|(_+ zNP7>y`s%pI6z%Yk=Ah@%^3u$JP}an8U9$P_lV|5m;E14$fKu32E9vqlhPAq{&)uTH z=qJq#k}fKqta(BEG6s=Z_C*>imZZ>(Y_;K|*@AuN{T8y7UAbQRD`Q~2a>gU4uOQrl^bZ4D^VxAHcIdb@BLNU^6z%D3G}IY<-!< zpm^KF^?}ZCMWyz?pC`8k0?ZDJDd0WDpokRe{na1{_pdN~8fp#RimQiJJEB_(D4S#Y zsB-?iM8J}#duc}Lj6Y3nkBZY+QYfr!gpIzaZTHi^)f=~8R_x%;1H>ouTzu@8pWE+D zGi(Bibo9#AxIjjBdo<;PR_1`a5jI>g8Oo?OAN%TEYzDf|Qk?raUzC-g%t!+XQ(3gR znv)sH%ATvSccUV+T`b$bord7se`5FynS9D645Bjak;5%t#rYMOp?ZWM;|4CM&eO(` zY@Y<2OH>@!x*Q%L8aOrJv3EphcL9dPqw6vPV7NqwwRxsNMe*tGf!nGFSj27@9*~%H zTq^!|`Sg!>kAe+f0T0!6fcMPv{;C-&?@tdCkJ~B+G(yPDK3V1>*2~^8e9BMB5>i+` z2849XK`9+jqR^$7Q4jXUa+-7n1J)*+92nO<;Bll6UJN!WXt*foB9E3LIWW|H<@pwa zE9A5EQUGD1#9zMrQ2qZZHqa>{pcP0Mg16hMZ(p6p^O86f?U4h^=WaExh`#+j5{~mFF|FZx4I{)`|{`-dbr*)c?fd5}#MTTPNK zUe3TeAH;?LFMYm#fepCu)YYT^n56mXPS!~a8) z1@%BhV*tK=Cy8Mz8UBu`1WCZZzuhdQgj*pUDe+GS{{Q?VMgk%L+YrD^3LYmvZs4)w z{@c#6!Jx-%l`7O1_8(#Z1sjhw5QPW=y+ zk9APRsH!LstLu9rVQ&_E+ksLLdJW`>p+kPhRo^mi8Qh_f9OQ)R2EOmh`#?YYd_c4z z193~3Q~<7%<%e8-!B;1upD*a_$ z!v}7Qa++2JIc)&J{h{!h>fqu#U34&TmZj_G>SHy^iB~6oGJnm2e?@Hf3UNzQyhYt$ zKs>t(6homLzH72Z03*b|#UdLzheWV00k9UiBbIU2Z+>3qynEB{-3s8+2Maf5>7IXD zGajlu48%d5emW?yQGD7*qGLnIko+blq7h>y=XT`uC2+39zg1?)AprhEeNk(I;07}kDI_-S#?q&7h570Dh~Y&TngaXc5ouD}22*x7pR z&iOKPN#7>m7&Itd%%Jb=4Ci|!O($If9+44F&ckx9<#&c`zeQ`o267JrOnt86x}}J{ zg6`fTuf=Sp%_{A8RCypmkqaYIDp@YZe64F9UB0#02OrxNW{r*Avpb( zngh(PQlQpj`wL$L;y+u){8ugZU>osW9gZz~q*E}Yxs3897#Iekw*fi0##(peH*CXH zq3yb5)a53ib$;Rl<^}EewtE~;0SJ)%ZpE$PaMJC-t*Y_lRP8&!8?k|JhUdojEjB~= z6>a93s){`ET*2i@>t&kP)mX;$Q-;L=w0q%el>KWmjzDNU*A9>(svAk6=hfzL?l<2* z?1G6H8d26xB)2W5(S_#SJ;zHU8jhF9LU5xbM$EOlr*&egC-Isw!}s z?lVN4QPFL|_N&8;X=12pg5EPqr|(~kTG2`2+*%%Sk#Gia0@$?nQ zBLWcRM(wEF8dE^&TmJn~rY44qH%U1wB(yF^fTPdCU38kV%(Dp)e zvGAUuu*MhI`)=qMB^!78Y!gV|&WX_U+uwNa;}6Dwv;leeGV2bgOZf~PwzDZfXULET zQZ%csV_O3QfgnZ4%RSNUPMfC`<%^_wvKl3Fz6zbcb-~RALv*BrsN+uVx}g-8T~fv+ zbKQG%bzm(1WOJQgy>>W{{p-AwQ5!a6vAgxuO+uu|awMdyciR&&A=MMA3~Uti zm-PoHG0=DMU6xC*pTCvTr);(sT`m-g6Og$EP>By;45=V*_r; zT}LTW=^JVFiE{DKt<&lIQMMV5#Q`mO)Av60h!uxVxh5bCi4fCNf&SqJ{r!V_pB(*x zb1E{C;yjAL6(F^eMiKGmX>Kxg)^6%vdCMaMi###@?mt{LIJLG!M|KwmEY~FGF&ZJ0 zFa6x!j-8T7-$%gO6gfK|aC*jhsuyteMElFxb|yiuVnR0Cqo#&LApxH0qr#k4vdW3nmNi7w3mpC@n#O%XT{ zM=8b_$6)t=-Cqs(8lLUIfHLT}+s&cpiP(+COopP_m+6#)M zSq?xy(!}>WZKt_+PE4`2pO0+OIVe;2xwtqtBt`TOO}=`0AK?bJ5R-#i$lK>>+<}@( z9ko{TIwBNJy#~DceNq{FQjq1QyjwobH->|!Z6fAhAd^@X6+4z{5J7-!wSfnqsb!A3 zpX@rR)qSt-{SzERTf|t=U*A3eoX+p%vV(L1U0^AFC|daXE4jOxft@tOJ8N3{_m=xl zJF7-f3{#-HHJ+#QTsOYidl!*&ndX4^6QG?X4UR?^-Mo>+!UJ}S(-s2uY-U$>4QmX0 z1gB=|0koPCRe|5NnR^8{8yJuZ2696 zNI%@Q)>p@CEyvpH&Cx){^Z+I^HF>np`aWwt4MqKlO&fnDA7di7U{?qP<3;W7 zWt+t2T9}+T?8NWpVxcTPSbu8l*fIDA>(~PVPt@pJf`+ikz@g5yO!AWcwyfueo52%6 zziJVlbI)buwr~iM%`O zC0fzPaer2BQQi@*Pq=X_b5=**w%}Ik@-9kJ?0c4fY$t`D z4(A?CC?bdC77Ea^1Dkp3)zQlhuGTd^$_g*?3kMCEt-s_(g)YXhubW#fr|_e}MKaER z6b`)Q`X2nWi(1Wu!Y@yM)a}q+H0I#A@iqWk7YY2H9gx=;)AX%YYl@~et zE$n_}z-i(FCgVkO$VGD0S~U3`uzfvVpFh8kSS?pL-?ERCs8fs_diWvPJe{Alans4@ zfbAJRcnKau2m2g=w$v*|2()LMnK(FNxCfuAX!;&av;#ZZ`C+4`reN0E)klt6 zXUuu&B>!O;{2bImlfX3ky02njvA&ZwA1^qZ@w)kJz&>>6<`?GTFod1eYjjf{x!AnBpiHbz-iF5W7tUKkK2&^nZ?CaGlb# z#t5U0?!ib++6KlE~cjHWhl)suak7|RP%9- zi}lk7)IjwMtxPkpLoD)cpSg};4yeLwU;$(9KLLfxaTL?C%jlP8Egy#)@S)jRyIIDc@jram zFYOQTpiHHZ3>dUEwuFJ~#xUR7bdCl}kO#EO98q6j$}vObjQE@u6HalswY5GVwKefG z>{w3a?UDqRWpCgb6UR!$EYDx-fedhojLN|{UeM)=6j(VMrd_~N) z9JL*TR6~#PwK~7o?ST6pzO0NV&*#BjJuH4(DXg2me)Dz^c#qH=2*(cy*`=B!WFTcV z9Tr*d*FAp0Pv63~lh>P+vW|re-WS&sd)@UiM8~?M#+Yo;JDsE}2J8Uahg)&XUD@M_ z$VkU~JD7aE7<-F9f)BY!mdLD2>&;SwiS2u@=_q?y&YqvYLz`lvfJujxLMwPxsXPTb3KZOL(P-9&jWlhpMNLqU`yzF(rYRl&4$;+3w?Ugus~ z>hWz+#B@V>lY8@6F8v!I#H#*mmzt%R)j#(f6>A9hwyLtcAanl}&S+XKRNA98ejo8t zr|OFREtV~0?U%PxoXM=$>~C}u&4+s12UYQ$@+{GDQu`){t0SBWJqh9|&*Y76zNGp9 z-D(*bX4mUD6KL!T-_Ij#(sX!=1u6NAU6Nn&^?RYLrX>sSa9lgU)Qd2m?h+NbE{hi! z4Tng7GrAA8VU|7ANp;4??^52(MezMWpyBstjUA+kL_Z7PBaHGUiyQzJ1o56J>$WUY z4yHmcMfNC`NK6UB2Hpv1QKul@ol9NFrsq~t3!i0x(;Nl+@D?F>zBiIcgxikKvD>fS zu#(=m9N@o}Bg#MT-JRyfYDQQ>eHX84aDPvBO#=S}3mQC{2yuH!o0$e|_l-s~iI5@K zXd@Ystppr3E>3jp4Ruqp%tq<1f08?GCW6kiT{5ePyRt(}!umf4J%2z2GL-q556}Q6 ziFv}Wp_|-~FMnY!M0e3Fi8pv^nLTWWY_{RP=+LT6)a9yNRb9Djka4xKSfgR^B;D29 zkU|i{O5=L35Sj?B-)u1(l{uer0u*L_JTT+Yg3^$+?w7dmmpySWRZcpl`j2!R_q>UN zG=eM7{;(~n;SK9^+(}XjK?x_-#XwEGS&XQ_BkxEilL9tjYW;JbxGi{vzrKH2#e)*u zC%nU{n(DI8y!LS~wzXe*L6d9W>_gPY@W8uhId4??fsIHzI}HVCeXT5K&^6$1^WM|M zdILNxcZmNm=cV57LnYOb*C>OCUN1K+<(Px=@*Udx+_lez=2tu#KV8NF+4_q+ z2}1WU1HWu~EOsZ!&@|j~-#)3m5)I>|S!R(wsca{BJA&O#6Y2? zs+K7faJ_okbO*Ar%l*U_xH;Y)?~{>LG^fO+h>v$9?np;8Q-@^XoF55Ghp*XfNPAEHGTyU5{hcsM1xZ9&t z3k45tfGi|1mGf~IS(hwS<|U~KKl}g;(3aqM9$x1(bW5M@)-7-MX!}--oiR^~hYVf3{CX%%mLHBAdNQA5e*d1d(7cb$HC$ETY?&kdow&qX4)y>8q_YRrKbj`@~Qhl{hT)#&>yxOcqU z6t9)3j2=BOr7`*l3#UVdH_6K>Yu_^M13X%H;&8j-ItZ6pOuYfC5bg<@BpO{VG0!NM z)w?$1@^-)tZ}RT@uA%N-{B?mFz(XchL^gdLXq5qv5l zQ0uC1YQhx-GeQjPzV$7DI*%eD=qc{WXduIDjBlB#y9qimCN(_FWgZ-eU+gBuo|Eh7fquR07NxDlH?>GG2seD$u>(8!(rlmG zU;kVo^|t!fhYg2ECcJedZi+Xhl8&&R#0gT<8iE_^~Iip;~q?H6HEr61;CRO9 z+wTmFm+sz+Bv9aAIoW@;`#WQSx%+fQ(3b-lQ~4@6=Nk4r*D8~l^0pr~O%nTT_Q|DF zuD}*?luY9xTYZ+o?PTaZ>U2Glz||qFM408=K~Ik-pO1NQkVj;eKhl0%5tVz3#gsg; z7v~wl?8@)^xYwoNWL_bYKW@yPPd{lD>#$Y=#sA3PrRN4NO+!Zc& zKR|w4Su2axrupm-N+ZEB{yL{=!g*|0j-?b`ae>Yu-F#nNf;oY73AV`@_Z2(HzJ86p z0*SWt;MnuYIaE&GZPDpqNJ4P2R75f-aMrcjtW$n4I_ZrkR$8|o?TF~LcWFBq3C8Owu{TX6@XzaFrA^yR_<9yMntjA90|_s$N`D z-WDPJyaLtY>S*$P8vB!=Nfz6a;a39KsZqW=JKKOxbyO?%_%4{`qCK6T#FYK$a*XL`;r!ti9o^TvAO`Dt=@`!C~+IGPmI!NJ9-}Aw5pm)q~n~z_)w_EE% zKl(L_=gSt^)iIMXo(?9x6Tzg#Lz8rZejwmHr5a(NNpw);Qix3lGol;9P+Dkp(?FA4 zxT-aU7@<7fU)N>-=}eZU*S^?;Rv7D^XR1oNQ8?X@69b$koXD}A=TSf>MdS@E)rhaV zrV`zl>oq4yDSbdI87=k~W}2_C$u_2*)2!ZMNv$@+m!GWPVaNHeqbwW16~Z-ojHcW9 zhLQ?;Unj3)Ewgp-siT)xkG>N2jA>ise#ep>vPUd!uoRNjPs>7pVIl*En{oySEm3!s zs=3BE5d4C*wQ}+I^0~$|1nm*+@x_yETRy(o7f>QWz~00@gV$qmjuVfDw_C`iTHwDV zeXB^#yWLY?9n&4G)JJG9>2=3_HtRR+p|XGSFpsQ}g{hR~_CDXouj7eL^CP9Nr;L^hz&jwB6by0dU|UrlVWC{{`^WXQV?65+KJF} z+lq^C(jT3y^1AosN!da%mWeo|#f0g_=}Yz##WX-eFVc6qiNowgzhY|hULV2^5?OKY zyvGdtEc(SjVW;g78gVKc1X^*-~7_T4#JRM!3+sWE|mLGV~Z4H#g+s zZ&lUjnNXE~AECYGo~-&@&)laRsF$QdnW=q7{YOfF%N;BfHGk#Gl|gK40T&U-OxZb18`R@aieBGEc6G?vgkHYsnD`&+t74~oqcQ(ne7Wu zI$rp`P!DU3JmX(UpRzWTfVP|s?Cu^!e;v43#K*^OB&D*Qq4GdnkBHq?78tdma-|b4 zOD%*(kA(pxIH)yVU6+=egWBu#WBMFaj6)Av`l}})09esU4B4;Y1|`xbY6{(Z4fHH) zKld5cEI)>jMs$UXUag(O+$->e`P*zIA+jeLzLT#sCcdrBg39iJhTc`-bg1FMfanbS z+f&wxQ{ztD4dc#VuBA!QHety_ekKzW+SVmx2H(LDC>NZ{7m#IC(>$9vIo?0WVq(w$ zIA9mt0el`%)cw#j|H1iP$FJTri#9?n9IEuU#O!s7m^MnFV~dp_n>yU^O(B;8y@b-t zbQEoRi5)C|PdS}pTv-n0H4H0G0%%w#psvsESl7@+V>@8Eqpx@>Od%R>5H4Dy%fbQQD&U2VJB78vlYiA|qe`;y_A8qsmASX` zv!Wt0t?T8UJxcoRn#meq^jPw@aSXI-rifCfvtqU)eR|xAT0^+(qqQa2tw!8P;!w|Z zt@uE4B@{=Lk16r!^{sp*qxsrr;`1;M<=pW0SDoH75l{TM7GX6syZQ99_ob~`_Mate zy#LL3qQ-xYT3gtuw9xzZu4{l(#|5#m8P{p8PP71h0O3yaI_=50(*TZP!DixI-y4?| zejDem!a?oQw91$%+5NZ21@nx%x(wdsnT7Mxf37W6zK^lo6o{Hzo7^e*J)IkW;?ZGx zeyICE=Hy}Fa2{O~rO$4w$&c7`KR34-;8dLX^>JlFeJ*Un_c#nPY1NW4s$QCPw6rj2 zUm(wPvghep{7JWiyI^eGcAd{estex3`7VI?rW*6Nvl^LdIHa4z zcRX!mv>cH<*5Ci9m~sBw$&UqV3>&X5%e*x5=|2u>#=G82?^@&&vjV291O#aV_8#?+ zL}MxY`yN)Llf7{#HFqn~=!k!gYx#=1&+F0kULsor>9JClU12?Hv5)^X@8Ut~7;YA| zjw!e~>Oz7*=dV&fyk4}4S6XvK{oAc&OOYp%; zP-#izn#Cw-{UHWG}A!Y#DDFj?*l zt+Nk<0!9q1VcBCEyKNa}Rio}E5Tl8{+b*mLbnrdwR5)`r<0U2rRI=JlPy1sR4hP;u z53=iB;THLruZ>do44!Gw{i1oS#&nO+kIc3iYR}Yjc8f&DY_7Gd=Jwj*KD7yE%8CMt zVewLV#6`cfP!7NC_?9WZY})}UQ>w3FMO;|)N}rpglm#)|)06R3kJJO=@0Oj)MiJYm zepTsg|gaYf>$<{SfT&nEFTcb?p+aRvcJu>JtiHOl1gNn#`tH zzm!}r)ssK4O1g98oL$XdyNyQ~|KKpLh4)E7j!5>rU-q;2yUAkD=TwoiY)?D^4r_eA z&XRbC@(y0_8>jl4LgMPR=D3!o7h{9;-G$2PW^}(E{hoA^Yc{0U6=A0PA=}vftiQN6 zXDHJ?PyUY<7Bli4YL7w5&@}-4gB^t>ouTQ=4K4Us2 z2Aigs+MLJE$x`<<^+xu>nVbn;v%50H`s?2|nGKj>#*~-%^l@UBvndMP(Z*_p?CT$2 z?fn#Whxm()rk|Vz&{DN10f`@9@QoM)y;gSB&QAWuG_OM~HY58Sw0VeAZq&)z@I@jz zTpX||?9|UTy>}XUFN;?Lw5Wgr&mV9W;KnnD`2MHkYuJs}*6rvH1dU@U-kLR^FYkVy^2{N1q>)TKd zhDZ&#wi|B((`P)^4*cet{^12c-61bI_&WyjEE^_3?I3o9Qa+!OSOu`Mfk-wpyJk;S zzRMS)?6t<5-_qnFaCLeeM1BCm!^{S}?yxcAuinIP3Pf5RUUGPKrloIrEHD?OMkSsB zzcBUhd5Eyt_d%*$t1|4Cmrxe9AA@;H=^3L5O7(p0XZSY6?If?7elwa7nRArW6S4nL zG3{8zZi?oB&aSp=wMzR-`S;)*d+E@sk!_Be+-ikAL|)JMf5IM^zWb#x!Ni&Z?=e8G zdI&-cHEOiqnOBg9xgg()f0F4>uuhHC?yJxvS~C5LZD_j49PKX<8(xCT*@P_RKw(81 z8FuMKt)H>M2ChKxFR4IoZ^cJd1JK8sz z(w8M3!A}c*{7M#OWvI+O{e6AF)$d!MwIKHd&H1Ky)$Gw-o$g%Q184s=Zx&w9mJGk; zSnk+-=Z?r{!6FU%K29yjoh#aan%SMvW3F1G9L6G<;c6ntt<95GP)A{rfgdoa0t+uZl$})nAC8ZLfqR+!5`N?hEo!wZ{&l^0J`Rb)quqcI%X@1oc#IL8}V8+$~b_Dof@*5GI|d)@!3`3a;6xLYAe{ zgNlcQS2pKdlxSKx? zd*5X<13xAgA3V^Z<9b51$3m0Jh*G>R)F5=vliwO3#Ft$9mE?}TCDPW9@pf)0>ARK> zKj1-9d0IE^&mrf}Y8$`c8_&_!(y%nXndiVYw46)Yzf$u*81=K@jFO2WR)I(EJ2%Cw z#=uQvHjOd3x=?hv$`j0=UODywcaIKbIb~+H$9r__VFZp zFLeZ-(FITee^Jh%!cnE>gag@3({F0tr;015E-4Uo>qy$ARJ=DOUE*_uN{LTVxSZk7Kb;Zh6-I49URSSGKn*jQ%Cl84Y=JYf4o$_ zAF8H$L@B6mxXNBuXcH{^O{nxl?k6#UKVb-ALjIguX#!+&>P&)p`>eKDhPC7?{bR?6 z{sicb^^Pu|(P6!W=I2Ha2SYSx71h`G1@{K#I{z!~@8~bLsNR4D87=H}qDelVck)*9 zvjM@rQ^fbRz^X_gUB-XNigcgdUdQQ1PPJfm5PEawTko%qc<3`eD?-vz_p~5K|9T$u z|0*(8{1}?Y?-QSXOW(jpDW334^k@s)LbD9}j@c!7*bX-}E2uE8)j!uJ8_VARUg*7F zmQX|=kQ1-$I}w>d+%0eTV)a(R51K|`nPd>+4kceFY-T^zfg9MC*1Ce#U`XTbpCe}b zi$1^6g|82YlE_kwidtz0Rs1x+^n2+4jh9t}U59Rb_ZcX#^igVC&o?^T6FJve&-PgV zkVi+OWm36QdW-sF$YL2a@m<$X+f#RwV06>?i)+^WANJldtjcz4|D`0Sq{5_AkS?V| zNofRW1SSZGG)T8JOh7s$R6wK~=?)1&=@O)*n@PvMrt5juUh7@|z1Oin?Jw^)54>mG z_q<|UV~q264(g$wId9;QtT!|H|H%KnDw#WfR&>w5I(|?Nqf9WunbjTUyBr(3^vk#7 zwjl1|fT+Dmi&GE<=DotAMh*BYE`LximJc>2XgZgS=AKUhBX8uQEZYZN!pL%CSH zXaA(OY?9IQqv`lFJ`LVOivrfXh@q>wljF$H?ivRF>a>!A2g?)3Y=aCYh?y9_gZRZ2 zmpq5Zj;(vm7x>`@m=!K`JD|RX6H4RsWU^Xl=GS*=f=Gi$6?d20yRLV141X9@sh~j( zURP*Ya_W?(BNB&b@5n{yNz8RSfu<&0Q0{dp?&;hFOb6-GM2L(1u{=^2k!6Z@WIpiP z9DyF{Sh=D-Jsh@=!JsyF%-LIOEU?3yO&*II8&sTi?qqeB?1VQmWva7|m%jMpqjW}z zPBO>nWFPH!JkBEI6jO5dC6ycJDo2i`XFK{(Aj44XDN~$mEIG%{Hx>Sglq?5hTq~Ai z#I12e`EyCnf)ax|AJp6rHNJkg|4S{xm%3;CMICCrH@9EB>H&80Vj5n|e(11Y@8=O) zG+mFGF0pAuXKb^!|Gn~xxedn5;IbeSoI`KCvS;!sQ$x^-OeIr=rYa_MZ%(t<;;0-M zmBEkUmw=2im#;Z+X<3bn_Kf9LnOszu!-6+IJiJb~6CqbS+HcnW*$J9yRY;idQd)Pt z&&DU^`*mv&XNyBMMj4U?v*S?-W|XkMf(@6wt!^~qBGp+`zihDFtuiKx#C|)*Hx|NN zD=m7QLI4NvKF)9!tQ1f7($6Z?dBRRy(JEiiiq0`#ziU`od|>JMb>@b#ame*@3?~l} zW`5I5BrT9{`1Ki4+& zkeB`BlR%urE!Y?Co=Ntose|)`_7LoD0G~a$5V7d6_A?T-gTT-INfe8q?^$WrmM3BvJJ{MZd?r_y?JX^l!R-}6K6z=nvV4s=6+-wOrw>Lz1GU5Z%GR31I>br>DrB# zyR{w13!n^-yGmw|R#et5k7aAtXy}=5-^poU*Ss?BAj6A?s9g#PF0jS#2}Y5-oJt~E zS_7vI5^X(~F);<-*gW~UfgE`JBm^g5`U5zK5A1nsTe-i zJU}7uzH}J_NGZITPm|geyS)eJ+n#hzhI$EGqoThw#$Q+x>=I6auD{C2OMp8eATY2) zuoeIN#;jGs!#;#p`jHBW;qdyG#zr*c$7p+K?QrpHwqwx+QjJg>tiaJd!^v3 zRw&zN8GMf@Ka(c~o~TuLiQUkbD_{pikpyCuHZLr4(J;LYIl&f7RdlJR&^UA}{x$P+ z<3i5iGal?D8_QIS1C|eYrHMFI?`936%^1&8^FC~dO0jQ0aBO|lAJH*tq_v{i000-L zaIMB!o$B-QR8QT+x!1+yU|xpGwFJ2*WGU(OuVrS&{~7*GMS{XiiTMYL-)3(>`^p`b zq))XgSyp(R6*sRfo;7I|2gMKO7P)BaiV$#zkBmlDd`{`fn>$g(GZ8Bs^Zmk>StUAY zsCzf`>Z781$-%^63UgwQHU`gP+;p9O!z~9jqa+c~NoXLiG2M@*%Qn&}K0hAc;(P*H zJ3A|%fG7In5d&uU$vcOLt$}4VQP0W36G%cI)r}hh10g_A`=6ywwE|8~2 z^gF!f-AqHB_gK9t>5hNb0Oz%gS%e1y*h$HL;BibYb9`~J; z0OxT%OPvx=GxJG7NddkUv`O18n@V6BEHwC*+-KM4Ar_WG7#K+o%}2vZ?RH(O^r7Ar z!J3(7$YO<<+WW-2pm~hl&v)#EERt*ykbHy&otka}S}FYesoE}bv$e#n0@DtG?#Ex-x`c`6uXb20yPxI$u>QxHLMWh0i=3Ta*QyJb z9nM|1P(!89$Ch-ftSasEnBMgI7B9pQibnXcudDRS@2!Vb$FSRSmCur z(!-&A%k(F56X3T9S35IIaT3!@>=7^n=LM?}*E2|_)8tA^y#HJKK)vSBmiU)@Rz$7C z5nq}I@fFQ$I1+M2_`aj*@|};9ZjnQZ6qhd*mXnRB~AH@i&-WdcmL zbjL^>8JW(`3MB(-CvmdYlv{Pn#F6soBnEU9cTK0tZ!Z9`HpS2}7`gLPPLclfc)XZT zKW$CMIRR02L^8-44Xmb^9k-7APLOstfu8%)9A7o-@r!2!=jwvq;3D#HfX0W zwk-6&L-1Fs-36^E%(VOdB97eqipTG%ocQh}f+duW!_ZewdCIT2WkmVf@^)mrvP#G@$jN%)2Rwu# zaYQX;J07y557!9R-Ml8405y>v&{}T#Zjt?C>|5Irp5_OOld5rgvrzIvZ3jZk7W%%n zW^z>cKBU_nqKJSfR4;-=l~#A1YgcS@&7;m!MPa(zP~*ayqk-F1=F*x4jOd*H8K40g zHM&}xn%RunL!GphqE~VUM#*7Vr^@75ridLz6LBMijs*g;em$$W2G>I&063CQSoG$s zi7KdmML%YI3A$~Dg8~j}p_1!1X-=Yjm1;ns?jJzOi{z6`(YD%l?r!d_*rH`hZ z(g#Rtna~x5{=0_JPl^3VpastYgCm^1;sU>w)tr_K zX%y?~c@@V3MEGZT@yEI2_+EQav$SV4h3AuZB(fCN*iMM78d^NBN5q3P3x6(tVM}Ia zf2Q*F)t_Y5SXWhsn+N<|5ARP+BUHJ@;qk?9s!#ehpBJJ*9jSz!UYHNYe4dxWWs#sI&{H^ZKruCzfLt#C)30_y2_l!S)U{7(=^x$S*?6hzfRrD2@-9Fb9 zxydkXnK!Vjt4pDG(a^nEYMQER-WD*xs=0mYLhs3ACL#vxQ*W6#0sQEbwm_O~IvghP*0Oo38 zafB!DI1h@KP6&iRn}sMh325zOK=c!GTT}qTS@S%tKE=m%BEzlAxfPqFr!OCPJ1{rH z_h&0my2X)6vai*z3?BR1vpnCkaG`)P1||Je^F3H{Fx^KR-15Mb&&zU@+cz!uES=c_ z(6%@0X~7??=k6!Lf<#wFM?8Oa&}I;VL1+oL|5KZ)<}uX32ePC|Auq`o!Z!@7#2n?z zafxzWmqsm0NZDg63&yY>E;N7b<`ubRe9Vj4Qa=2g`ALQpy`KXRZqY%?_O;*zdbcVB z)O~6vtda*iaGS87tN4+L1y|w2G$NhhDVZQWf$q1i+9JF=9f?u(b&elxwqj@`uDQv- z_g|k0lgC+PxQu^{nJY?G4@OPo{E#vQx0XXOD*}p=)ms=3+Pn8+?VDuXp^*xdOM`}V zO8dd0Quy6P%Y?X-^|9L_4q72=o>I3kwGSFf6H(SZ&Mf)Vwa6zn#QB3`J2MKl_dyFT zHlytYwmjskuv#D6;xK4|WgE&>K)knssyg;dQYt9vkBw}Ro8;S>h0T3|lKqx*=p#1| zNtCUvaE!P1Sut)BdF(?WV556S-AXgb*!RrH68F;>i&&l_k3I6>&OFPOJeXU+)(>5g zheL@raeb|EOfI|YWYhN(hxRNf9c561R@fd3+rE>PP@f>giqG~na{l&kpMz}L^gyIE zZ#H>R0Qo^!5NQwW*w9zYKE;v5%;Sn ziae24;-)i+l1wWzc|+)|_cU<^#p$NZGML~>Z%4=(d%vh6|XbV zF`{NcQRGRb)H2smsV;`@W|BB@s6eYb0j7;UY^>eIZB%qnM%jcgo{h$%MWuz$F<+EmJPkv0^HFGI z{G&p&8yy4^knCM*>Y@4RQr+76L-4SaSG<1L` zzzqe4l27g!*4eLpXY9~6u>Uq;R6>FVMLkX&nhm5k@8=YVnc*e2-@x;@R&~4zCcD;K zUP5=I^H_cErh|`-BmIvQjTy-=St>?3rxh)ob%Lz4kpCh1H+OALdM?|u4sq!5lxN}7(EX%sSQwTW9^^apBViVgB5c3_AX*pebj?xO z1y!rq{CUZ77zKPN*jssg_rf0&X47Dn>sh4UJ9YtKX-*a|3e1d9+9XKajHKHWZk4hg z^PxbjkZS3UoUCsTts}$GSC;m60yI(s4efADL=Y~d2-`-eTM)j4ovd|%osKX>E*GoF z{2%Z_R4 zJuE9(M#J@U3`kE@M`kecT#sCv1j$h48vep!4tiW)V8}*!DM#&( zBZb>N+liBHopzZL`nXQoeMJHTZ-WF<7yVwrv$nf0pAD(q8pzVx^=d8%JdRhut~L}! zgq;x0g%c_%u&heN+4Vg%Wwa&PX7a)Jffy+L<|?<#q4|B?Hy@9pa*^H%W!{S=sLPI` z+x;5KmOTBycOJlj3+>ijIJ>eUza=C-3@zEKj;m-e8K+B`yQFg zTSpXpSP4fFpAqcdy)7%R@{9+I=U~Ft6(2RMZ&i-UkNCAxaaHv@JkLw{+UNk=T<@>u zN3JCWG2gPh&u<>UYoLtX{nVB9rb-YV|8mpHEe<8!J^(6y=jO+WBNvw~6cOg6Or7)7q)`F7 z%pHF}P6-j+vKg+kzV&okYTCFxFZ!vVJC{rLoIumMhc8mdclrP@cnV`LUcbG%=fD4z zBwDh0l6ZAM=1d z*HknLgez)r$6xlCH-fY7nnOw$g+uxZ6JH{>HE4j>q|n9N#9;GKq8A^6Ng=zWm75cW z&czPi`@~OICY|;!O)YqKfX=lzy=$HowJ6q`nFgxl3q+W~N)fqNPz~o$RMT&!Sr_O8 zVxOG~qy7#!9@(QQxU*%g{J1EIxmLss)klN6!5o%&9E`p?_XOd=ji8MlR@|c6MJ732 zyoZz>%2PkcnA)Pp1_0mF?kuU^Z-k&i7Gl6*>hL5QM+O?jOGxvy=wOEc6>dr72ay{% zvcMF^4g4+_v z2jKRT<9T}EJ=BdribdCqY6cLB*$yRRH2*9g(|6@5^iY!)+ZC~{VO5IwKZrYc&Jro@ zM|Sh0ADFt^GjaB!%x~fHEC$jOFL7gjS^nw=SsIlVGJ9LhXXoVCblHE~wOR%?jZ(8J zQ}*NyYPSgFP5OyWwPM1mK>IB-kwx3YuL{s=Ds~E9BMq{6=}xKFc{I#KEs7{+1Bw!F zX|x4lWon3&nn2e;hYjHkiNYox_q-FzX}M1J4WH)eGAjI#7p`@!_63@IOmkvn%tfY! zASx;}@=eOp+O(IknKpqpR1qlu-t4c|h{2AxEE~q_;Obsleo3ayCL^b9S@xWDrKsgr z8R#|4mk#RvTSO-(Nh^K^I6#~j<(Y9DB3VPv>YXA zt&I@~-sQU&JJ+BNSUqu${Km{XZR?HidmR8`~BxL!zZ=Uz7`5D>^WU%57XejYlT5?b%Q3lH=^5Jy~F95ZpNl`WfpdfL;EA@=~2ivLc#f!6G+;4Zww`G{1bU9v1_ zYQaI-)a!k|n@6x#{R($-PRiO>UD*aDf^kEgiQD*DoJJHzY}yjO>q_x*=vImJ)ds`n zV#piw*2nqI0uyU}6d4=g*Ldj`*x}$W^vFBqxn#+Oa^?`n*$cv;r+HK`vm6Wf8~O;x z+uiMQRA%%w?{kdJWp!B$71_WRgHuG@YCbgfr}K^ z;bGiBq$F@5UQ*frLx!!44QJ>#_XwxQmwRePf+I%B9ZG&AG%KNg@G+>t!;zaDhfAb< ze9wvr2?PTNKcfNvv$e*+YfQ9F!cHx!HRQw1c8` zaHw;_dvBF_vMXR(9l&e;dHKsoByIvov|<*Ef~}_`yt6YWjQtR%x!)!zntlShAn4yk z9?y^|>_7j^@0ZR&S=B8nSgOOThcSO^QhN6J<6sxsa{Nzb^$|$`5Q6ii1LX+s z5e{<-oiY-@4Ae~6nySL)lHxy1X6^wD8Q0^hKZjZHw0I61nN1*t_h}i<>B{g_LNW1%(~&>F+eH5-T~CBLT{h$PyO@Wz#|1vGA&mq z`TzJu{&~gUcOT#i?yOo#{pLUZ=YRf~&t*Xed|^e$*MI+w{|~RLQUX^#e{=q)mhnH| z=3lR0V?$!&5~=0n{&m#+>lJ^GC7^!9HQ6Q}ZTXJ@@b``U^*N7pKuU76V2g+E|MWKh zcJVf-CRr!Hzy5oW{QX(~b`kPj>Lb92)iDo^{d>gz#}$7M{g=t$$_5Ms_y5~nBR}W6 z7Qo=uvx&mt|Mi9%z?IYYKKuRGU$TS&j4G`u*o(iv&Hv*KP5+Pa_a77Y?`QY=F34Dw z^x-oy{?{Ag0#~}?Y#9I7U-Ey4=Kl`OzsJ{qE+zjvH2-(i{I~t@Ul+6gzgJD3_h?8S z4lRH%rSAQHXCDmwao+!|Iy#U920OtDELR#Swl(A(NJ9;ymb1|RwzRjNDj^B0;7xeM z_F5T{{HRTxdJ;7;M_^x4hyEr-^}j8qCYLP8NDmklDZ2yZZ4b^u{--oPAZq51inlx? z{I6R^z&+&4#ZNBpH3EIw5);BEpmx#}5B~q*#oJ$EX!2N%U**dhc+MeFDTCrC={)Da z@JJJ+hd-q`6(B30q4XC!lt`-l9{8?qMf~01s#%A9S;lri?ILoWa+yfVEX)gF{Nryl zqAGrmqiKK-c5_7ltqnU}ra=Q#4;S~%Z-N~^dZ;KZ(t5|z#Z4}e7#$NT;$My9ZH>9F z{d)X>-`)anb;9*-1`bjS?8aw`xB!I`7DkV-7#Fy z7?4j+jd;Nog1i7N?dRBgUlJ4XYM0&80i!6QvWQ|3ie(o0UQ{dr5h%8qk4I)E;K9Bc$ zlm9JO!-tlon;5@K#&n2xIxyhI|sEK*=0m#dGj zr~}s0od?6$r$I&p(?$Q_E6`VOFMzQYoh;-`^&_*{8Q5ws0ROJiEpDqNU*MS}Cy4}m zZLu8iT+Imve2@+e0Z^5HV!d`|I(pn15#t66Mt@+Sjo_yDeeN=*7AYajfLOe$AtIy(3YZ51kRS@?{edf$Y7T? z9_YL8)cGBw4fo-e{dAk*G<2QHg{7J&-wvg6dI=VSTT5_8Om&DuvaWaeDV)9J(o7dn z7`!s`{s-@i*UN4?>GI2FehUUq-$3NerDaN8%FkTuXb_S*H#Qo8wd9ei$z&M}*?W$M zOiby%h?PCaVryX}Ef+Db=w-$OYnxl+YDGU69$?OU7s#=lK$buaR=X)+Q7MaJ;m+0mlpVu@6rJ6F%Km6gL`_T`)%S`ZPt*x~N>P z3f*D39rRNW&3w_nibB)9xL2ozY6Cpa9D@Z4i~dOwqdy1hrnOgvEZY(|BCM9u{}oi6 zN4C1t`}6X9)J$36b}iSf0Xo_C-g5lVk?D8@O3mMtFY96v;p`OIqu&Phr2Ia|Y?)X4 z9g%r#{s^i0BU(|L79aO3gkNwZ7tK`FysG;eH|iDu0pcTzI8dOMZR%5ESrlsy{eU9S zyjr#%?~idF-+EhcmQd$4>~so94KBRzROVy>YpPmK!WoGrT~t4{a_R^10lGwzlZJlX zk~o4z=hGm6fZ5bm-*Ry5)^hRu&aE#Xy_yz-GzW@MP`?Qexk(d@Vv&TnqH+}bBXI}a z@l@o3y-(04zW~EKz^l~k4AuCJWOJCJtvc`1n)2c^inC*2RenwB4A@sd@%jtKW?eFw zKQ@2gzsvOJxF4u0STU$qviDGg+aRA@)b|6Lf9w~nt%T4cG-%~3&{Q#Q>blKhd5fpv zC|3S@Jn|(-O!8B#W?B#4eGzP77r-xH(@^;=V=vpx}HX48S94cQML}n=8#* zvGY;JpT&j&&B?Fa=bs-XTIMwV%IbC*QCHpfIS;< zpMbvD)aUa-)Z;7Q{u9L>!BgPO%?`)RzVJI9L^rDVI51 z4ppr-pRbEw0=X4;Xci;nrvvdEq>*+8$F@Uw_ed<{gemiR(Kg?x{xkP(A7D&aEOA^O zqlGkflb?EVo8+91=hcMYOEi2`6nv1 z`N)UC^$J9BZ_hc-&WD^A?zRADl-z3S2>yZCLr}iQ#(UKGy~hjFza{~ z;30?1LP5`5j=pX6m`I;C%Qo88>kSE80)(GXxB&WfmE^WY7&`yA2bvFgIk^eL#lBSjnW0@u3(jG7Pon(4d?29 zMt@tf$fu-I^BQ|5x!Cm8zQaRcN#sw(2+YZDihzk~6oJhm+Rt-WJ2zCFNL`dBV%Axb zwkk?e1cCC7Z{>Oe_)wJCHLWCVkhPr3l461@-3Zd{haOnJY!51n1fU zbU&WTje1$~zCT}+m(+jmdUh9GXzht{JY0p$*vS#m2`HaPr^N$%D1_9=ec{!CU4u?! zuGh;%Y-e{n{kN(3>}SihNI%E19j~pYKQsEA50(|8(4ZWEMH;=)ey2OMUaFS3hLtijHqBK0E@QI z8h@+h#&-;aPEY9-!6%cb4}Q~hj`U7>T5FF#!kc6Lo(GQj)|0Nb?y#KN$*W&WrMViF)C zKg(Rh`<@k61=vrJgZCXTm1q}Zodx1GNV)W;wp{o zy&j2K?#(vd*buR@+tM^wl;e_&$`(u;Xm2)_@=N8eH`)m?JND8dFP%Be=a|GQj`1OY zj&dme81?xHYH$liheW>)ZwWtRyau9WxCPp^X$9)~!rI;X@;U_E(48_`S~UcU#3 z8;$yoU3amfNEXHD{mVbmY}Im~ODhk&A&Djnju>mXij+8Qy%gxzV#ds zl7Bm$eU+EcCrW+SJMUHhiXyr*J zbKSt{mf3-1{(gB{+?UQf3mAl{S=2i*0y$bAo9K7l#ShXouuRB?$c9i|{5vZLob~*S zod(p=pt~PuhDF2b6|aRPx2HjnpUP7DK%Ae-8308rOMY<05gf?OJn^xAMLCt1`I+oz z)xM+mD9Hvkhn3l9YhJlL6={szn@0^JZ1ney0Vp+<*Id<9MQjjHZO*X@FC&OACu)`a zF|^7VEP89@@>;z5+o|mc`9|0%ozc=#~Y=o9NC-Ux4TNHlJ@9L|f7#f1iKa=Rh`9 z?)ebbU*xYRzg*;gxv={;Z9czAg|h}uymwzoY+-)9R5z-ZE|S98|4|clE9k{3%%o=^ z9g8L<4$A^;q@%6*HM6h!AIw;Py+n{kILrlzQ1#3qR1+6+@mzsw6q+2p{&nC@O|BXq&!>t>WX%DLL>bv zR`WS6I@&>WZS|q5s1BG;UIIaH$#&j7=A>2?(IhkWR>)*^>AKq~oRxR}RbEo#>e{VE zZQ|TlwpI#GHDToDlU@G)-No`XPTdhQO1RBCKzz~3V#JT}!%A{%uLH|&30OZB)~E$S zf+{>#70wi?*Kbtc3{v;LZ!?L&pBbBPvPe_q^k9a6y)9^%)$f}5nxh*>$n^e4v(UF; zbYYJHomGvzmf3jiHP?P`7r#B`o!5rz{-(3x(Fm}s=-3_>IL6w}6IH|usLbZADO^|I5%Yf@`ohCuxlO|0d{<^gc{v*LnBbA{PI?SSyHabbbdSah^L&!iF z#S>=+F+ISP6P)v*PcUhe7J~!?Jv1SdJPmys>1C1iWT_{H*4@}Np%XpAxh?SOSHFJc zQPUG;i}tV2)MDM3CtL3@Qkcuoz=9XZrJ?h@B?r+xDL%mM`M32`nxm*S%Q%8gDVYwy zNMxqm>%|KZ#khUYaaBohmFxKi>+0bKQO_PhIZB5olwFBi`XG`Q8hCHY3&IAGs1JgJk&e`6j4R#ydrR@&PqUsB zZ@68TcliN$oQuG*#tBTp7?Y8)QNfVxX_ynY=BViTyQ5%}ptUZ^gF7J_=S#&h1(d_f z4}z>V(0d$hWhlhAtjCqzyZ=74EwIkp3IK`j5oxlbDAZ~RHG`I}3Tj@#mTOUyWMmn1|&(ThPu@|RQ=i7#T^LmB4c+?&td9R{!U zT!p$5nRiU49Sdtz$zG~7l~jI;GBbSQ!=P5>h%F^%O*J!0+8SdSEYg0KV$;sj^Ry;C z(hX~6LSdsOD#jVp`T*M=bTW`{6K|88EzdHISDQhM)Y6v#{hjp`b$rudwf*lHu=%P;PN-__`X`04F(B zL}(}ve{kMtM%R1u8A_z|+Jh>*04M|Tg&U)P@Y`zjw6@nE!Sfqm&X8Yf_XlhJ@99m< z#=5m4LbPbrrKj?={5%FM(Exybv|tsKc-nNW_d6qc)QKd56CECToE6_n7CnpgT(Va4%9c&}dsTK5zLcawX zRkh0VaRvV5H5v5R?z`$YY3b`$mB-M|Kdk>%t`>=MLg6$sK=y%Fs!4gG+)Q+ z8W>L=C}W+!ufps(-M9XY@8*HAa+$kbQ&>{J(f11IQVW_Le+8gpLNK4t*b4G`{rsWO zviC6(YeOl038X*`n}ma($^6PTl5OYVhqZg^@#HEiEzz7b9BC;1Ru$uyjFDXEe2mFp zF|!jJWQ^I&bgS(BMjptP2khW{|6~d=O%gR?MZ9)?)sreah!GwYcVe5`{(gdqkjEOz zYYt9y-!Q*Bk@`WWJ$6k^AZ81ky(5`Z1McF*b-&YAa-C>;+2zO}JW#8YHe=?-Z+oq+ zVIjP>pGUcFV3WUp2J_OI(ffRR(%3O1v;?;?vEh4g`z~7S$>yzI=k#!@fkl=UsFK2^ zT+1d1v-{;lg76_><`Io%kWRvgykXp4%3?bk?x;elA?1tQB>h*vd}8jualDHf-YaVO zuJLW&lUa5nl14WJa@IOyxWkbSBWyXlh?NAM6&7cHy(Vbt-$57(olfYxoVdl)N#BQ) zO@9*f_O8$E1I0|j*S{i&S_TX}jG{l#w(mnP7+^)RUl-ki;1%}d7ggsuH`sz3rXE9K zcww1PJJ!;bWWQqCZ*_g1@>2{n2?+eBL}olb_bfK}&03Vj3dJgq#&DX#-;;$~Gn|@y zw#UsP8(L9^iEg6lrf2cuNRj5x5QZr~khx<{Og?9?fR6wWZCkzMmjpbQhj514J?|t_ zTj(%RsC&{&T49MDN@-!6ebW!$ru>6ZPi)TDQh@_mb4L zh*0x{TN5j8jrCRrgqELK%rmXB*DW2?a#S(O8qLlLJ{1KjHrd@pb7b1Kn)QlDA-!TO zQK2+$wkLY((QH;B6OYo}umTdmLmsQ{(^*fbdhB^VaOUokvK|Dzmu*_e_?AP({51iG zXs7eVYQV$Y=K3ef9(&itYEo=N3vPd*V!Z3MU3V-z!gIJOkl63CSoS}0}w@SJ`TA5~~D%&`eh zc6n(jm?$}9#+NSD4jZGxFptGvS^|o)iJ0AGd(7d5rf&bsbmt+;QPdSGup8MRzA^c~ zJ)XASebq2ZUy!HJu%iKce?FYtY)C}GH|($*za)CMbx~g>3kuQJ^{ulZbl=)%!E}ZB z*Sz5KY$b8DJpA?rddk`Sz1PsYT-I5>A`yl3Vq7vm6iHYh9d15pGAMAAtp&+|a1?Dx z%QLsa3$_!ha~dErc{=XGXiC-b-t=AZm%hpX`}+0YR^v(8hmpx--FF(V^@CqU942Ow zu-Ltm?JdnqT{p<#iHHSa%~4#n$Bjh0ExXrNCB42+hfYgCw@^HCy;vZkGn@d4zohvX z5b2IQU}>ww%JvZ@`o!fAYo%u*l9Pe644js*bW+d3f+(dL>0obVpS2Upt+nw5%ir#% zfGj{A`l`()1v?w-Ka`27ory!@5SNu|fWP&5&)fRID17N1MgvG^NZlK5d5p1aq?B#6 zOq5M`qA2MG&aRYIYKHH8h*}8k(=@CMyZC7cHau||X=nNm?w{aYZg?m0~Dh%z4@TtFoELq0G_)9`x z%3t9-);40&KtTJ@$b)t?A3iY=1^0V=W-Xa(F-unAk81UZ9}?0sMtwq&qm;&eMm%Kj zlTOJuU;b!@h@<_N=~f#hXV~HWmhX`39&Q8@^5WF4J6Zx#2fqD8-G+L?1r0 zySMTRaCA-cnY580Fr1dTRk2 zHQW|@Rc9<#MOaX;a7EbK9!aslE;G-khV43wwaYq3L{CEvGP-&%2)Mr;r1*NFH0kzvdWa zFmjH8bdui4uU+a?P8dY5e^bpbjlx*Me@J-Mrq_SZe&6!i`})i{XG%(Q;xY6{dcQ}P zu$8ceuvS0#4P(P=o0A#0tj6Z?eOAa*CK+;zvnpac(-u_;CDbjD(VHXVR<#R{ z0P4L-M4}i`W>3^!-n>it&OWn4o(8mQk1?|jsOPQ!3dC1L_s=dU9)a|O9EabpGLt6F zv|B<}!^;8NE6Mi-YgqjgUtA(#rtd}38s)L`x-6}9e{;}3ff=$(M|a(ApVTLNi+ljn z9&x{L;Gw8S=qqU?92RO>FG8tZp(!o{4V2Psl?yCtnPMghoKfZjt`hf~bZQA8=3y_T zbG6S_YY7?BEWY=6=z(gX={t-BFmD<^?&)@XhC9}2wX1h4Z`afFA4Kznnmi(Zn5(hY z)}L+l5tqh4EHtOoXWM!tjKGFK`h}j6%`Ve|ct|n@gVs8$qy{R7lm&wgy~D$MkZ|{V zW4Al+CD%JPi4o8<>S5(3?$^wI8QCq$bq1zSmI1gQ3Y4Gj?lH6%eq!CH+8fYV?O(-+ zp%cTJ_84_+E*utV2`Va#%*bZ-k1ZwaB623u@0a;(CpNzU`yzKvg-}H4P)bmL*P-$g z*JOdyfO}JQ=9UcBv{EKs=9%`kyjZr2w7b<4%Q$IvwR}Q{4Md$-CeNz`Yt4v*;?T3m z?G9VXI?_clTkP=TyC2d8>Uw8{cOP{6feBKEO6Rl?r5zH^S=lZcFYp0k2Djui#}X84 zRpcH$m^AYF#|+tN8mNC0b|@xoe)?=$VY=USn|qhEL~SD%MPL}j$W2`SvcCHfzo)Fz z3_F@Sn?MM0F2BDuOpE&?-i#p_i;To(twA5Vy)r9y>qG~@t0(}o8^Y3)mDCA z{^~6>D#hqdKoRKYpna0DIAMWyb(nSYPOKqws4^Hu3?zY{V8%`OTF!v9Yr04^_hGdy z1s>Yu538D`HZ0m_KJ;CUS!HuU-Io$ad(vY8y-Jw7WuWHiW|GAp=XGJ^wVf(UP0IgM z%;N`7pq)_0tOkmiI15}4(b;N}IONCWHk#>iTz5WnwyP9J|1vMbbpVzyC}CN^8%!(b zl+{7h%7a_xI>~KxDvJnxz?h^?GhZyO6C0om;cn=NEE)rcv~K2^Qd`|qF6#2Wk#4B2PAtm3V#+LG!Ov#jxbU*l z3!BI#_Pv-^k%CN$FvQ-R0u0QN+X1mWF4)1v8YBeAQH_G(_A7OYAM&^yx_uX9AKf?t z_zL`6pu{@*qRLpfBQ)l=n5X*$;}hb!=sgDnBBQ<5NN_QkjO)-i4 zbct0{$@9A0fLby8=Y|}melxb36X*q@oa`s$8=^jf?%&<$X^(E)CDJxjMjN#06_)fD zQhN^x7b+P_;W*eG<7~2@zt^V-PoqKUXRv>cA3=JY3Fkx{?HPTdJptB+|GT`=jE^h3 zzpT)c_I4sPPK~^6sjBB;Y$}`QU1y&Q!(@sf>(F^C{xmUNVfiXb7yEdgP68Ki_qN4- z`HQ<&IV&`);o(qs>U}sLeOyiBP5|`c%f(hTid+McEmdZN%ADGA=u2w%;zTKlCC+Y3 z?2Mq&CGp;i+QiA>o#r%OWZ}d~ZY#euOD9vXuktz?Tdl@*x0lda*qHlPS!_+7<1XTu zqp>i=^VoE|ydH%VjlyW}C?Jh^_Y1bYK5k4b%LehvkBz#Obmbjb9Kq0iSK@OIT$oDL zPv$=@k)@VsW{N22%UhLx_dR|$`uMMd2A7ySZYfq580OiE93A z&`~eQhPV~_el`g%YMJgKhq!v+{Pw$=3NmNbi>7}$o{u7sei30^bq+x-vbw50Nby)r z6)i1(YG;jT>U{?%Z?MdC^u#xAn>{=`V?4KS!0w@0)H@=M!Q*R|_32K?7Bec`P0;8?0`*54pT1Ae1nr__Q1Cj$ zFrQ2LRVyvXKBWi~U1%51HUc?Tde?G^+p{UqTiKqk3IxG^G5y}gAa}A9azf7VwD7H~ zW69q4qR63aPX9J+d+|x4G9F#&~)8rM`z|# zXMzbI&jb_PyAkUT3TurBF9_y?vRlntyjwCqp7#Rg# z#;OsUGJITg&?vpdBQ}cdGGWD#E-q!mBz3v4-Fp!igxwW%r?X6(#?8^@%DL9oJAsyg zYObJIgB^8?(h7~o)<0f5Y!dI*GL*lY87r}6zo7@^vU=wd* zP(#$TjClaxosx6{F^EE#>rwgMT29u>zjGvWe{v+oHwYCg*QL;rqM|QV<`>B=jd4vK zX_%=hSkbpoZHgcEtd{XXT}b_0NS!r}rb1$0f&xI=Z%gm?VEAu;W%92Bu8MN9qhWie0t>lw$bGN2+W5@EPqpraD0o%MRS7yabvjT1o0XnEz5 zN4ucfY?yejZY;jodPjeogCR*U@c5+Z#K(hq0T|zmHP-HeBI&}Mj`$6tMH+=M=Qo8l zy!0mh=31VZ(9-Xr%`&)4AN}~v>fq6L_$dIfQ>dk_XZ|Y>k4vcKe7Z2?0YpB?FQ^|& zKY*92lj*b3d6jT`S|m%ev9{dA1`@SCU_K3*>H?OU4v(>Bi7+5oTC z);)Y9JA&hOcfoH>jV|IlR(>8&&3IIqyEPEJI%t;gJ_DX2_}pCA78Mwk%^vn@X%EJv zg&Us}u6`vrlTGiqAE-mPc`x{J?K>BD{go{5pw_+MJH!;cC9Jn~P#ABZTkaFphZ2iv z?!7R8#l|)@%=s#64+1P!@y~r%fN)?5w`1||5;1^w-gj;s)@_KWXkUx?f;+L6 zi$YrYYyYwxz3BO$toYYG4UUZ! zZ95g-aVh3X=-NkYBMv)#t5`(yzOUsNC3qQz?sISYb}==9VrhB%g_BVJ1e$JG=%}a| zZK&e^#ok*-McuA@+>|g#gUTQsf+*cFgn)D?DBUO_4boCFl#~cagGe_>cc+xX&>ezw zcf9xb?ERemo^#gO|GsOz`=4h$Yn^kkGI>elXC6IHq`DhvNR z&Q-d@gEm(WsPKj_PW>?$rV4u$ z5xhfmTu9~qjRY0<2Y{)RBh+>9xT;SiQ0Q?f2gO<$EyoBybGL70nc0KH7!%rfl!~ZU zsexM1kU3LUHp;z?v>&syw_`RaohRAa&;2Fcezj{$1Wmz(aEl{2GSmphXCGa9jpWv5 zYf-4^%&_r*HlG5I@1f<>J^ak0ZEcBhCH0E!^drVmA9;>~MsH5EK|2x4b`(as@|132^sL_gjcn#?+Zd z&+>5$IcW_)Ynk?tm}^tcl{dUhNjSEi?5qoEq@(3`TRqseKHB7`+~NDjnOT#bgYgyz z4QCsvN(q01Mag$3PrVXlU*PsZ!x?^IxMEomrQi1$PcVFCNt+};d(bDs))hk?j>0#6@u+z2ut5#gD!F2;w+z!op)B8J ze4&C@J7GY}Mwp3J8|Jp3L1BA6xlzRKegCu(@mXhiC@2#PD%Qz+A~x^yN_WED5J+Hv znQ(FeQX+0It+-hp_%o(Y0&S zTV#W=5xWV7pgD~?X<6bn>%U-w2+Bt#H;M)od!U*+SfkY&DgzeQDj0QX+b&$y;-xLqpgX)vY*j% zPDJqGKQF??zQ0Po&9w5QhGu^cmmp@bF<`h;Mvy=Q1!u6tp<&S7tIaZL3&gk5lPR6x zG+VO9A5ELRane4=iJi;l)3N7Da-dvX6|A)S!Mbq&PLs=iaDR}T98&Z--v+iVELe5% zk6zC#eqYYVKB(`X;gk(txA2rCeRvRdl?NIXXbCWCZ}Hv(ptjxOlFJd-8CM#o#X>}n zXNvc=8-mT^i-1wu0a!LkY^( zG!O+B)}9)N{5ryf_{u(Pcc;T$pbKG18avLzF(kLHe!>?{gHKD0AfaUjO1jDQHEcdD z?}}$GZW@K28nLNOa^Q91<$NG${c>UOJXGN70Srj%s^xU-|61ZYgr&JhlQKjVC{ zRwclPH0rqvRv&+(crR9I;ZUQaJDA$IrC=9d@-d3OqT2!SFcKW)mYf1&q%2NF4d_O< zBUm~DQt-FT3QFCZC)|i`&Yb~LxZscnn^krNQBa)d~3X;FMU*zzW6ShX^SR`{}U=2_YLd}J8x8Vl+s%)r6&b~6LEEu zb61z>a@9Zmx4UpZ1}1FE+)qcTWPyKObWpj$dT}D`BjOO@dg7d*y^=e;WYPp0?O`5v z1b6fJkN+Vvz`&u79cqD!Yrf+)SeFklB(+pOfS{^z0@=ldQ7Huu8k9`zAuHRvK2Dj{ zC$nIJLdQrpk7;^^>?3i0@}cSnnVVgD0*%K-r@wvUQ|)oNJNV@7<9BK|2JVbqX1u9D zXbg&#UWFvus1gk<2GKVqn<;j2zAb?;%dB_ZH%xL7IO(zPb4c=-?mF-}2l3zl0PUIg~IOWicF}Rbpmbc4jNq zG~G|VXUBxN^~h8P$?Tl?f)NW$$|s&9=pFI>x4@^~e|0B4iR_SGkuO=y_E7B4F1eN< zUV!6A({fQ9W5lCO(K!k}va?72_3o^KtHTJ%h6L@lAKUs1C<5l z_i4#a?zOzNGE|BCbGE3V9>GI4hg%%*7}_F2q8{|lZ;bRB%bw-8N^-a%ZU%B!VX8b& zo(b;MAABQ)o#>D@uXzxsd~6hd%+3}%Uw|$NoXyB{+?o;6^+)=2nL+o`76mHV+AD?G zFJ#u$Q6xDQQg&y9oQ#%qb)ybuV$NS=ID^_t**3ZKsY8I6<%Us4wmuJ;3cb}mqrK`? zE*Mo3hbjF}Ua}EpEDV-T93>~V)?bnQs^Hj8zCm=LTXm3Q+~kZM01fKF3e_YJTD?K1 zJ{4awqIU~7W))oT2MX?=yNp+!N{GLnGKUy?gHek8SDcK*vr&wQ=K#r^X3!Nzu3^gS zy;H7dXa?tjnYoz~NfLdce~#&Duu#~2fr8q2$Fc1r)kW821{pNH>CRq{s&P;rR@ zE~H8%&81ja1V52ZqNPMS%)Dy-zVD)C8o6UWoG|NAs&XdyiBGh*CfTQ>qIEd`I(&W> z65MMRg>~NvYAZg;rwaDz0sc>arCaT1AEKWNz&v(?+shqA1_Pzy9@x`1N9 z)n?U>sM}CC%`ypdG(qWrnd>mFT*3KE{h*YV_2)8_dWDI&3=EhUkG-8UDQazfc@(U} zCsw=5Pz=ud6%hUWGto~;@69wGe*0cFM$yG#@^;2)^w$Q@*S15#=4zX&lO9fn`kdXY zR)NEsL2uE(+OvLzrd)gv-U2+o@MPy{TJqI9;PhWg$c`90+LDqN!? zIXH%Imm5D03~Dn4g(_qaDnQfME|qF-u3>BA%pK!m9At)|4oms0ouM5nR1Ep__O18j zNJPGlZOwzh-UQpmvjc4nCA4uO<{O9|116tBCfVnv%MSK3^A2&l>XWCdZbcDZ4CIDT z8hVKs%lXx zkG*z4xlFz+JGGd~)v%Wbjl3)I&q(1H4>YJE2j9~?5511#Q(P0v$CBEvA%?o0K|LOy zyzogVc45r|!*4L{q5L)Kk7>7kv8cMKh&KIDB!kLrKo_eDu(n7XPV{1PTrFtcn&dns z+*N9kGU!BdW{u2^+8Qi#8U`xN?zo%|rWFNh>~x{lTSm+4ol4v6^=Z}K=Z{^>Irf-C ze@bG%1V?w44C;`vJFWPhPjNjDcXB))7nDfcdsVHUkv2en;h*+RjesNEM2Tm#e_^uV zfD4R`nYEpRQMAMj(Ez8=%4lB9DXymtI;>9_nh%2A!-$A!aUw}2`Q3_(u}N1S`eRl0 zgBdujcfT~-so;1ilJ)wtM@23jM(C*vL>-t?mPKI?eRew!K0NGVLbi&yes2kt68k(9 zy{Y1*09t1y6K~{;@iA=Lx6~~d28q5>ds?@v_J*v633UtB$l&fk;>%x`>%nnY)S@+J zBy*>;qjn$>(Uh2bgfKV!oUzwmVe!wzXDsAF_-SvoIXD+hFi5ZxRzf&--F0@Nw;h2g8PHr5kO^oYy- zON1n4z>tDR>rQ46#hLB-CWwWd;sjhlR%q417t6_~o?CQD@54Oq+|NWDq7>)%$ARaH z4Y$)muZVd0CtgK;{_5c7jogY;hJFzO9`c(9KBZz&J{D@}TVDtESoXuyQl15Z80qnE z&>N3*2gznJ9BHq=h97LV)qOhes-u=Jk0~FHz8eLB+)RU`Fx#wWL6toDamq_bT|w15S%JG?dyJEW|>o+@CRIXYv zJYdj+PU4lGeiByfEmD~F)_VK$^Ti;~Fjihg)DW-RzKx$L$*`}!Yuc>?AB+WafTN%g zDCqNOf;BH1&rF+9v>940wp-^<*);IF_)LUzZe24Iw6jepSf+X&%TYEO5LlT|!}3QH zInuzml4pL@aA>CcL<#pvM6(l6e_k0dOET;!9~eQkV9f(VOd<#XB<2APBVIvVQ`zBL z$ONBonw5!RDPmM7yQO1o`#H!vu15I#W6ow zS^zSiWsta|tVD4JVn`84^gD45R#Hpn4>K%z$rwtXUr_so7Zf<3&?XVyisuB)xK+zf zM7lU+sl>ec>)9yj#-}Yj%K;Rm{=Cx{>vMMB9JOLVe@_&X27s8fi^m_ZST$W8BigN* zvW7zIvg21)ANeRr4&WiPcL6FiaHh~m9jnr(QzZU-S2C zwLz6!dG;L_gPDFcDn+44i+s6hznb@LhO@L|5KFu5zkfK*woub1hMN}2@rgwJ&Q4M7 zm-`pHax*J6uM3ERy;xV|9>VIsYRcq*hvdDTEa$?(XjIU7I&+w`N_qdfjj*pwDcQX0 zT7^PrdNpXN2J@tyJ7`aU*m~f$9PGgz`n1a&v#Wc}i<9s6acLRp-3dy@+4_@Ri9a)5kLpY9evmqQwqxOl?KBQ3SKjOBo)1o=gZW}t zWBC&0@*@L!)iwh;WGIbq%t=neR(*m=4ySS)8UK-C*+_2A!8Rm-?WUtjx;4>q<$(Fi zvkTAoqCu7H@PV^pwJ!7sQX!>FOWtRh2ZvKU3VZy&spo!gj+jlv#2XSSowobm*IoI3 zb$-<_brE{WF%>pIMR^*Lr3FUan1s5T6i);XSh$(eM-(aXw0j*n4nClwv(%AMaF}=c zNOswc^3YiI>bNEE3!`^t4=es|%2p9-RC+zW12bb)Jl+KL1JGbJwrj>nuw6hFeU zv@`qr(}tk`4h<-0Xcn??<*qpJGIuKxJ4_ab7zQDZc5OVHs!9J9@FGqC2~9vb1{0wo zh1N$)zPk@Zs$)CVIQ&*fQsadCL*3Mtc5IMzDDbrYku?DgRKFEa*dqX*S;&JDDTXT; zJ$u;it3eKcH{;LXmwNxjA22K+f%2l_a^SkBxcyqS=uZ>F|3E*BV_yCK23UzmVd3Gz za_3CqN4tjZ*wugiUf_zm-tj0#ELwwsPTi2F1Lq1^r7{4Xv>6jD_>W{c^82iXH|N|o zoOz9C`0qTP`6F2$r)(fkV@cZk9zkj!MY%_?RbO7O3OOWJdpZ!J^86F|kBVU#_Mq5|` zE)aR*igD4u+$td^z}69beDXhTpb=s7!Ny9gL6JUCn%>+y`dn528fv!p@weQ3vGyPiUj|^pYz{8{qIjTYl5rusmr&%``Z})=bQermP0t0AXnjVC;l(H`QP8_ zTMDjjRS*q7`)>yDuO|1`N7t~yvq>>LWcc5H??0d5pSPO$16$N&#y+6^-!J-KuMUv_ zMwCd)n%v(%^1oU8-*4@_4X$3QO8iUm-`)BzOdvFKfBz%u-`=IryWr|3nGAjZ7W*Nt z0^nRn80k#^7AFOL46fcOFBeDfZ*P4HFp&*xX%!?B|oC80dct^#5K<|1r@2-+EBr=OoQQS>s1(YxBR~Lh5~i(`oR%J*@L@eO^u;_`~pj z3(%wS^+I|)te1m-;RXH=XU6dccu{G*22v!9{eL*QfBoPZ7T6cOo*gCq>x=*EUY0Hm zcDj)v52JtMZU6H%|8qD0uNdP$w)vkW^nbXJ|2U-oxcC1fp#RS<^#A=mUHT=;#cvgF zb*1=y*(1QKYCH%3nN@?>dL4u!JZ2Ay-hlLZ!LPU_NfD7MCIAroze5yg9fq_LipTLp zss`wtT6#;%?R9B(wHdAl zqhL6KQ36QQ+3tW$p&VQ1y`eLws+3f{_qOIU>A#KZpnAx>m*>S)Hh%2^0LnNF&Cy?_ zYpmWNioISYdu$6L{0Lyr0E+SeaWQ+*xUQCZ{-WYQqfr$(pHgrQ=!;be_MK!{uK|v5 zu#m0p@DpGKiD_7uZB_bt9S~rL@}dEjp8U~hRijhE>+hF;PQlF^LCrg0IONXcdG9)_ zt(!tc3nsZ@)B%!{g}?>9nf=cEvR{;au8)8kmPP|8AR<84W_yXAzbz7Jla>IuhjR}fW=(lcJA7wF40;`xy$OEsIj1v>d<@}qfl!ZedUtg+w&R|} zH*!&(pZM17?>%7`lLlmovIv2~)5;srf2}bHJ5Ze6K-S=q)>NsD?3wl>5X{gv{hgU7 zc5^m}&~urK!g^?*XX|;8h$!u%QnUW{I}7myi;^PoD!Mt2ei!tjs9S~`q-&cm_~(N; zpI3b=gSdaDgT!|ru#b!fLsevt`h_+M5bqB9`A2O0yu5*p=7UF{c3$OuQT66$hMb>Q zBG+qqCqR5qN0J|}`PXD_K8in?zqx9Ac{i7XH+`+$iC_{|VA<&^cx@L*Fd7#R_m%3V#6u+h=NW z5uXRWMg=JV*U3`C-gvr5Nx|t9>s9&kHRT+b8gCZ<5;%Kd=IfyMptb83D0&ZY@{Gj4W3Zu|MBi?Xu#`fBc`!TmCrDZkbp z9zO=og)+UwSnAz2>=jG=GQn}{e zXC>X0w;`qWzT8^}%$C7fn<^i4aN$R=G~Mo1^9b=;6F z)ODU;c>yacwy9nScmq&stRWV)o&=?L_VUSXLw|p6;dD)NEh1H(y$sT2z+FQE_>R6C zTz{iWx z{nB%pd5KIo3sM-LC8BA{rC;o{-EBUf0A4^Bwcvv52=e#pe+JUd>P-9Va}e|;QBkMS z-(`a$bBKahw@U6klPNg^P1uEvZu7n->L^pL>3EGN%VLxcYC*FiJ|jnhH!VkdV^^ z6z89EOs`u4IBdZzuS{Lul5H{Z+H%eH%#K&ANRXzuEIQ{>Z}wO3OnL5xuKnUxnUT+q(@KWldUta%tI^M~ z6uRZSbILDqdS$6iJud=U;6Car>L%Wb#g38GJzs#cE^3-)HnPv48y!z(I*sb*8>@3| zyl`4aJsxYi=3R}{+Jq1O=A(U2oE0?jd22huX?{1FPO(Sx7{%`dhy4=f&+G1@Phk9z z3amcaqb(lt3UbuY+MZ44-Vy)xK)THxq~FM5_f^JSNnVB!7{TsAbf9UDpuaB}Y*!Og zjj>dQ^-XR&OIttXjJ;%OR;SSNIyMS#WvrKGcMYE&c&PFmP^<;diMGdx+afw zDW_VdObx3Y-j*sk0aN%0Bw#rFyz4L<`$n0pGJmeYHCzDeWTt3N*)yEC8G@zxnPiYQ zjcbZ>?uCqW-Spl^K=f-$6mjGqH}uP5shkG52TX%bo(E;0nY@ky&BY#GC{K+zufD>S z6YZ9)J0Dr6h@{^CxwRKMQSIeM4J^3UI^Xp=Cv}&-cNKqu>SP8uxeWMYLT?5 z8$AcK6wIJ|Y}JhEBjDH@s};@n^jFT+>eD#kaJ8xiu-ThyC|-LER?5uyV3C|KroQ zaqRWG@7Ifjck;HIZW?{-X>?i2`nW9Y+~#>KwXeWKDhd}}&shgURE1E&s5KV$rqj;f@KkL`Nn7-E4Uemp#g4_pF&@=s#r@o?A_J zv2kkM1AEvf2F#8X!_{5-@EmpR-(_c2r#k>ST^ufWp0kdG-T6_BmWuPxCk=q=6lERW zyV)qyRF$M^Yy8(WFB6EqKFNm{o);b_m0NqzD$}7iX7PP%`HWUsZ*wmvKihJlP15X zZ(vp0k^eeYr*hJHD%h`=C45iqk841#DZG_JhojB1LG`(d*^@`@Y?JPxec*v89D#^h zs3|o3ho?kWC!|mFgk1#a|@^m-Zy8X`v*^ouLFIz z0OOTn5~Jp(G`X_nD2yHd$D=UF-La^V4cjqnIVy z&!XwK!%8)qZsCSXdTE7mAiBlUixA5xruEqZ@#dfSmM6SMOe}DOzmt=q>8JeTm(-W@ zSlNP&(?ixZfK>F_O;JMl$-|zkw)7XYhe*}h?KfNtE zF#i5q_32{B0S17$PO*3mAOR5^X~|#1UTsR$VNg$g0y?u%HCt3~TMw~Jq~i8o3!r7FCkpW|6Py66Heq{ZYHedm$kJc3;`xSF(Dz;R=Qqt9O>fCF7?7 z;5i;=MM-OaHeKlp-ovgX3X&C~qXY-3@=Tk3@~>2GVHmdCiL2b(iM298uV;-$8nQeh zmahJ*irl~eHu&`5@%KbN6L|zMjt4H+pLHE_eH;E@{mk_R321)Bc~;h6{pg~iex*q! zk1{13jGUW)a}>_-tE3TCIv!B{h+4u1mLA0Fe;(_BR-2zYs1tJmAZ%4V_8%3zK6I#1 z4DPozSFanalh=|j+;sDIa0B>M&~w03<=%P!{PhA4%0lDsoEs6mk5pdEfo_#%N$5|^ z!$9MA=Od{*q3i&}exnYo?W7FaX}H)L!Y1!`)ItaKW7S+(3GfLrY%>JV!LybbT0z;R{OmCn=C)QO)y7bcFLEO?l+(PsgBV2Byu zvh=Jg-U;}9vHoNT_VUJ0Six4hrtz=8t7&8>ImolEJ|Pbg!v~xzmN#^dXn!F{&gi@| z{_t|DXPnPGF1vhINDc;LMG!XCds(o!+q1Za%3@1>6rF@Bk`gn0pF;6=Ja#U=adZkU z&T_KNIBZy-m4iR*;G`x*dNkib>YW_MMSZQ2le4FasGgP_biUSxlfE(du*9=@Anc! z(cji0qhA+7_?e`pUJo?n@v9e>cLz;g2G*_jgj>I0`qj~sr@iITN5fZS(1w7edarM0u zWw(zU;j!3}S+6v&)xB0J0M}Mslt5blD@HTs68n*Vdq&~6od7$zE1Kt+(^#!Rz0l>?-=R@*@N$cCr{$>Cl=JXz^~wg_ z3lNGF68am;dJ#6nop!@-P13Ame09wZ?jfR3nCcPvNV-pGIm{~}`Fxyth0e!mN}V&0%nElP_<>KC#Kp*DA7QsjmZ`LI zmW7YpIl~q$MZ0hQPCbc7AXULogkC_}3CRTN$x&J01^zz^%7B0wFTq1Poa_{L`HI0= zkJXlL-ZA}H;gCydEVq=Jt`#jy8A{JSo-%ea9+Ca-w&5Ul``N5Py(mt|&Ld21rsQ|> zDZj~5UgCaEQC{q-=BZ;R_Ji+P7Np>jOl5v#2J>@fRCo4-(R0Am9@A!w?HLoFA_LC56>D~Xez@{FOs9UCs&iH* z7>)P-fnUgczc|LihkZfhknAl|T@HNm(@+mEMSN->TkOe7c6ZQ{94#_FI=`@1KBdOp zZr^yyJUwi27xq#6bXygoJ0E4C z-{Ni!Y{lOxzyKoyE|mS{p~FF-|a&#*6%a+*x&s0e+e#&n|4^!}OCp&Vg~ zJT1N?Uz5G9>)?Dau|>w&QnJ^p+n$Q|l_65=UEs%k6uBJ-Kk#RNXVhFWU>jsO^5p!b z(jw~E7GD9h3%({kbD_OnCv|q9!+<-jp=U5%+kj;jAjoogJEfC8u>rDTH1FnY;?KMUHTm%gL|U=ftmK3Az|0EFxem!Ki|3( z_alnE&3V?~p_kz}yO1^y_#Bb8Ji&mwNVd0P-3zJ+EIN|=xj4}-GsCYKR>E_hG<*r0 zCzE+bON%+AOlLP=S`Cy&5TzBD9yx?T&-sqHmf%|$C4_-{&Jy$3(y)ljV}NmA4aS6A z{|M*IU1-0Pi{U(NK!)wV@k9C9b!Oc6W9MKwr=;RTfmhy>7#Nb1W&Ju{!pF%>iUsJ=B{ovctH%`Y7)sqQKl2>t#`TdvX%HIs%szg zN3%6}?zUQeKS z6#`b>^#on4wP3U4Dt5Tpv&%~Na$+!L5cJxK9}3S27720m zOLu*2_l%OC#qGuZp>=LQd%jobdR4+lY}EJui^->!(MwXh&Tsze_#bAEP( z)I#yW5Mm+>a4=09^N-(Wab1g+wlytTij*3EER~gYhx;-+8zmr;>Pax1HvFTi1)f0g9$MSA#p5l z$UU%t$N~MW3z9;w*nB3xKcC&CqjHF|8_-7B1Y|yx$_AfFubiJP+P0q4YSPyBa}UBw z-R2KAM*=%M{IH+Fs~L>iSKS%vom|=0gBvg8n3AJAo`;TP`Zgk`45cn56e*QItR|F% zJK5%D9Xu68q#_8l1TfiqS*xbM{obuF)EFeXvZxL?Rn_N!As|}8K7_ditFE7EUhq>= z>k@wLB}@Qhw|$~k;RSa7S=Xf`-gVxiIz3^slV>+zrsAG{Mkp$ya*_ZZeJ2i#fA?Vn zNxW_sG-I}LUEue=>AO>NY;9qeg?a-a{j`R4?UIQ~TOhGuL>L;X8S{eySn7 zwONH6)7`y0C$QW6%5LK8@1gK2K&1PDcrtgcj&Eysg~#vwmO@_|mlz2=OHhS8aVkx} z^D12Q*SJ;28zC<+|Cci$yQm!n;f+S=+-yM30UsSR5Q|=)k__YSS5qz6i`M-#`v!$q zy~rT+J@x2CC-@cbx~Fqi1CS*-n&@F15#L!3v~$|3ZI8D`(L+t>`e;+kGO-YRI<_%w zGD)eXYTTMF9wlt}iy{G}TEEFO_h+5PVO=G5I>d8cN}2TXi6SLz`pM{20$iiF<0v7{Dj2@xv6W zt5rPL)k+1u@tvCL+X#f#zF5JMz_7i~UMWn@)!gu1yTE;5)FBtY-nH$awB}|YrVKm=GqwuKBhUh&x0ihJDRGj*6aQy703U_5* z;DzP_8}3{#&iXhzQnirbS_IIOglI$8KdT7At*TS!AMQu~#NY#$hepgCk^bLImwNtPqZRHTYbJRJlk3Xqiox5)r zqe-GeLrt8fxM#cNZO-!4;1kRp0$4p^2wltyEa{kUR&J}EyWWdHC z%-*hauLOiKTvI(OmK{J}3p?}-EkunBabesU$ht$NitI2fkPTu0LFLkjlSdMeK)*3bbNs? zu($IU22szkOM_qB)}uw^)bu>h9>m==xcN3PX}Q8n2O;Yb=lm&qt0YP_F7oPR&i3P4 zu*^6T4-!TUAFt>3cbEW4fc?#OHDwW2gZo863b^0EPl-fjFaC7$lvGcbRS%x`0oG+U zePM^eff+`fxRLIreptht@dMX3fmT^~EvjMz;`vkglH#q8_n&H=xBMq#_@JgW-r z`07nmR?{=I%^Yq0SdvQmMQHA@8cK-Mn{`XFiuZx2J31CmY!1$(`Dg@T*B0 zf8tk4sp{BiC`4a*YP%Xi9uvYG(EaowZ=95-&;U8@jl3;orHtT@Vrd5Rn8i~!kh*&Y z-3L+27Vcr;{tKIk)!O8t=iAf^G}sG)-S?R>IO=nc$4w$E>JN;Y^hIU1q?{zMjb)iY zrA#0FjCn&4O-ZCce>sXHTPCwqvqus&5vr{UjM9QMK6H#t%wBicObnxB*Zo!f z`0|XbXf+#^uM>Msh?*2ZEB)eC8wS5ruRgX>=woJb*B_l+EuUZ`W4n*Py9sP*x&FpG zdPlMyDR*n;1Mk*k-l}SO4EJz*M;fCUM}U-~4Szg<7)YOsW_gCX(4>SYr9_S3jPA5@ z7v7=zzHfdq?EqVHV0{0PFacYwSF;Rpv>$%W^tTzG%OcHq8kn(;ZN-YXSxLuhEWY6< zmuEOl(9=ZrKM*t9gxp|z-*!Wg0`M}6QsOJrtot&22+$uoGeDrhO^LB}11}~n`S@(G zP`81eOfyB17CM#rQuL;Vf-mQeu>6x>Kn3NEAcQ;^#d*>qTiqkO#XdW@qI@kh3JReQ z?H9eEK+G@~Jj)+pN5xI2oqgR`>Af5%*6Y_#Zd2VjNf)!VZh_|uDwUiex`4;Tn?dj% zTISCz*-Px#7sfvW`?&S#abO(yLb#94V z#D*la8sH+{q%wyS&=$Q6`ZgXR2ZIS0c$6)L7at{hJn-SQ53+RGpV)Gwq~eEnnuKM` z()u8FxB;F6*q7^a%m!Bn?`gYcL>11)OClRq37^=br2U6uSdSyvPaY#l1+ioEf~#&! zoJHmjv{%7U;urzy=0{2VT+QL!D7YE>SLyiOlGlYij4P3Zj=MjN_ob>NFwsc9LN>B# z)%i1>(Z=m2%Lq{di379(!FXlrb}q`juYybY>S@kK&2e~7K8(EKl4M4DM@4fziB0DO zd6nXQw?_w)>$-{#h9XL^+j8~n%qF91o1>E75WLe!2I*hXst{6$`27oD?G>XGsU|ku zOHO+l9kKUf2kE*2Af2~=5EqlEm7{O^B2QD&{Nv8M)zkV)1P>OERkPZMC*6NU9->BJ z&__z~4&J+-uFdNd0H8w=!gxL*SH zh0lEK4V9c!_k<=59qS`h+Hl{;Xqr)w7gXcysG*iD-*zS3ju-lwqlZDmL6pSd<_o~ix{Qmu0Bl8{?1SbBY8e}y^i z7`437j!!Tc;f#~#04H*+M;L#*Z4#K^ZgeY+K(sIS{&+5^+7KNO9%<71SE$Nnq7vTY zu#m6U0mY{oFbv6DzDGHMj%)NPr`=tHwmpo;o1UndkQrZb_F_3LxeD{d5tR4M+JsUb z6gaA9MM4Y*MK7$hmyQai2c>ptN(07Re%>!}6*iJ(8+(9*?j}-h6i?k~LeV9QzseP@ z500U5l6=SDp)Vn9wQFCx(T+98sYPx$hVn4z4HfTqf z>r0eRD=1i9Io{W7jJ*KJW@YrKTQb_)D^9IAG1g85Z4OOojY$4c{pk^yV>S4EwDL8~ zJcgiNR;#WcjmW*ZdUl_bSUMVBMSq0m2rV6vOcEQwQvg8AU* zA!V`H=mdR5uiCJEY1j#x#P|uI%}mD{3cntBg)tuYcY>t(5Gl6({w=UvpuSOC%gEZ; zsFz?3>Qf$7)eftPd(B3btnZ=d=ii6FZiO&J8s*$cF$XT{xzn0aAYO$>xUGtSsH!jl zn-_Jg#QxQS_jPtH0EXm0FwkR4yYuQC3?n;3ErW>kBRN85GMwq2xutmBHZ)LLaAyM* zsy9tn1l=KS?7P8dj^>1}w058VfWL(8R_n))TaZ82)XDNF{8*Cz^MBhIr3#0;qhT!w?9K;*FXU8E}!76zRz~`GuIFJ(nW) z(V&9|_Fa^*Z5qXZ1L!A_<_yFb_XUj`_(rWQEXI~ zjjtHnDJDhglLGb`LrpeP8}2m=h*?v<_SZzxfY^TgG$ht3T*V4l{Hr&4h)AZ%N>=edLdk&|>aBR6q%_^Xap@T!^5uu923DpF0%= zyra=q=@c6JXO3=P%E7HQWoNH%pyLeEwewY3)>?3xb#l2!K9_{a79qB``~_99r!Ex@ zYV;EFJ;;6)kmI&x--UVnvkWKZ3lMRyp-9lqFPCR(1Jv(!TR!k=Ah~A&YH<8ei{uOl z&ZrGul-TuNgy0?O)yMwdexd*$%3^wIQoedWv+L)x6aJr^CSrDUhtQ_2^5&&qH5~9%KoD1Bf}( zv{8d6)S|}G3m!zG8jUI8MfZv1f#0)42H2HmTX7=bhHQpvj4kH}Vr(%Q9C?zN*v-K! zESdB>?d=V=Fs^WhF~lV3kAYKq7s#|-ZNHRWwa$eIttLt_o#kAL?AkallG&c zZ6PIW(J@Z-e}b&erBJh2rz9Y8`n?DvN8Rnix9vl23B+RjY5d^3tl_q4mA_jcLW97F z9nL#o7@CrX{wuNHH8wL1#p8rp5lV3-UQX?iGL_ZoV|*mN#)y}qslrR3sB2X5V%-Nn zhEXNuMKXY2BY&2TJbbMJ% zcp=sRr2&+XQ2HZk*S3Z9)bW%Go+n9D)dc|6cV2@NOsmUe_jmIMvX_z5F&HjxLF`TYk%_Z=E3 z?57zI-$V2hrrntOjFO$41?!StG1VWydS=bGUYa&=myPz_^xpuEyK|lNwMnd=GyYgt z2_sM=fdBm6le623Gt-G7w;jButZvc_S+^?icZmH6@N~|(g^rFUo^{p11 zoUP}B)8`OKdzPOcZD{O#92X;FGVK#wO|r*B6h7J>ysr!G!M=iim881Ll-|>nc zhd;STRP?;fDgSKARbt>rcHRSLQ>v9gtG*6L&oP1A>`!K=+??*H5@bdtnoZaXU*fdE zY${L(wR6}MBii2$6uUGcet_&Sj80v2I!$RvtG1O2oiL*wb9uC_aYv{Z^TulV7Zo88 zm=1w=;ZnWIz-IROq49c)y?#`7$M$)7!;AdbpmCAZ>W>+^0f`Ioula(Qs(xZTnS$TlOp z)k9m|k@P>UI*I7J+>Bz%e8f8pg#zt&Q4ohX)dLI}6G~wvLEn+n>#~C#dx;o@; ztxfeuF}{eXoPFfKbUM)^w!LWnh zIdNy!Zfyv?jmnOvhm^^Gl$A>1U%p7SI!#=E@&Ym=q zLXv%5U+RxvkTwbM2AdR+9QSdnWM8lp-_=;2`GA5sSP1wIacAR8Du*1Zk!HAG3#?@z z1aP@_nNa19_RxJ`QB3zCqYrJ4>;5E!Le0?nZyQcL4n7g3A}tVpsp!(hD+fBlM$2=b zqlPXCQ0*Ck^bd1NrN-QWyJ!#_#o#$lM>_@yZtBGFEy>45kiF?w z>Q4sOKeF4?^QvcGl%{Y~eF>vUxub@!qV?PL*fMikD?Os(oUqn8+>&{9kMPX2p&h8z zmHv9=Yb<(j0<0+~7Ir}7_6tZ{Gicu3;2)FT%$nXa?n5J6Vo=q;V7}U$@OG6)HgM&# z#rVfBdYyUbvxhekb&$FIlA^3VU(X*tni#b~{eRed%ebnywf&cpkd~Tsmmo~KCf$f2 zppcOs@u9ajNKf$PvfkaJa~-0%ZqAMF26ALS*pw3+#tEQY%@ z4b)GZa~N<@;**-?N5NNbqJ5n5{C|<#wcz`ZV9Psmljy$Awx5`oaxNz6V(*L+Age9A zsF|}R3GONj>FTtpj9NM1jHXQGKabedd-FTLy>;<@npjuojMHvkZI z0bhk?D3yz>aZqw}qa1Ctig0)M17baBm_leMkXSkrCS+_cvrge4?piXZ6Lv60y;6<( zj$+_adV4zIN7J2EVc_1jQ@09$l!a-ZMxL~K-PyaR(dw(z8*J>kMz&Ojxar(KN8N4q zLAU*d)x7uF@KF1aEQVm(K73mq=HtK+s!9sdX%319u=c^G)0o}#wQCU~ zEegTe6T@c+@%UDSLl6v=VUO&A)N_R%QFUl*^R^J3sNW1RU`D1jRVt(fxZ=4>->fVI zI+P1$qi`}zhAaz1e*EU7`EVrG!4j(GE%C=j4&`w{4q}-OVo~k+Qz{*4RE|)OdkK^W znyKEJfw4h`qA>&tmFOskV!GWP+GGzwyLX;#V*=Q%VeBD0lciY3eQ6Kc=A5KXX+3bSM!%(Rg>WeUt<9IeJhToQy z)dSbaOhW&D5~`Y^fexGJIgPF+nS0{rPv3fdF?15!pxh`!(SJbA6u+iex+~x3l6GK@ z82PriDMlzGtk~_-M-rx(5uYE_X>Nr-eSYzp{lI&t`o$pQ*vDO;Cqo{F`$gVsb3r!w z1eUjeH(8}A&X76$&tMv0?ij%Vn1Gio+~}Pb!$wE-n>~M~BUG$$c+S@}R9(plsmUz^ zqRIHUZHPLKu&Bjsmv@daR3b2g4DG*PT1n{LyuA`UaXy{UjG+4|rjINZiQbVTKL&)2 zNy7PEaM037C^IIkz=0k1ELhC^EY}AKO=Csl1i6AdZimEO9Y4=qP0zj0k^$tmRPN)pD%BfMd%#lbBoLqMWL?0`0H_Yw?dnq@B@zhWffFXJ=Ab(h zL$yzjyd%v|=jTAxXRh&&P(RaovjQR1Gn4kD z{yfqvz9s=hh&$K7GFM=dnu;v4Q6)I@clY4Owp}6^0X|%#s?tePFd7s+mAyV{xmQ=g z$@EhoV0i&#bFA+qh;ucpF8Gzh&WTttv9kNSZ_OEFYP_P~f&6Z^Qus?dc&3;BmC;SV z)Z;lW1p2aH3ojLm`g`aMXjVoHhcN;;*QHXuEMRH+vzhz>kWjFO2 zUR3JxJ~@|r0FAb;rlh2xN5fNz*;G1vzS;!SI(%sQ-cV@WW9YbqsW{FT zU3l{*U#>6RBPvN+$jP=zo-MzLiq6IFowU&SQ*TB;2mOqgqKKZrz7?K?B|Ja3cTVCn zPZKOzsBFj4P>RxCcf?^5Aa4hW4fGuLo?@g5S_~wWSU#L%ebp3$_dOVwdXX7SEG4&0 zy_EtTnpPC%F%N`h`AtA$#2X}AJSpiv`EZr&zOvWFlV+XJd@RT`<gfs8Mam|yIwGh~IR{}pTw_%`qG zlZ=q2tqS!aBAu&PIC~ArZ#I)HQofi@2Ni#X!@k$>D3}KSwsy$!7wm|H-M%C@8#}s@ zPb)vOxan~f9&%>*#%RI1a@m=pcls!R0E-A~(juyxIuYDW1XcQV zwH-2o6#*1j(}PyA)u~nQK{Y;1ERVWj*F|>`GHMH~rO5f6iTtn3C;#Y3Zz&+bcHDco zO`8O|7Zw*$HrM7M=3Mgvv2M7guRD_>jLR22Gg~02Z?E{=glQ-uOULJ~WnY+0!n|AA z-~4fD#iVjmw13ta=t1#~tK%ZFO!AJOeEQqo+|XWYD8V4~&=vrInvWR@FuyZWiC=jkexS!VAJrU)aW-u7(b+dB10JZ_bQv9TmrU=3b^f zzaA@Ce(ISg+VMq`vM_Br(O3E1n$Sr2>+h$m)EVVfrAL=AKX;#kQI1#5i57i$8S~u{ep$DN&GF|7M@|1x{|w^Yf2E~9F5ZO9 z-CgsxOsi28JaaZYLC*yAOFv4_YyEwzzHc%o{XqZ4)uU?~8g#wic;H6F$IShLfT2+q zu_(p0AEh^mB>uk~cT9>%1j-1W%Rz~zb*ZnqF~|Lpr$PZuJLN^UR7blaBy5T8l9r0es(zHt} z3*i|Ol-7%VGYWZJwkeELoUyd}U;HEgA=<-E0@b`zFKw;Y2hHcUPgzQb>Khg5nI9U( z$_aUp{B2vh|6{e$m7gQpnE0EC{U5)C-hLJ6xU+Y_5DL?@J5tfw4x5aZg&iO>(-U=^ z;wIz!t^G)mMj!q+Wakeb_;XsAb}#??x783_0E0*ekf+bMERtFz(E^$0wlUa74`w$K zhv>4i^Rb*p{aPcnRv9#s~lId4O*xmc_qz$w#CKd^Lzi*7u_YnFGh44aLCO z$ha_KQ#nY?l<9S>xUXJ=*&()?f2p$fh*% z-yiDV^N0U(68{;#$1uNS|L2e15wB5Lqo3+;cvMEvjD{NGRWe^?g( zTBiTIHvjh#`oC-;|GOdm@Am$GIo|&NIfX#^up8wnj*Vt`spfXOuG-<| z`0XrNcmP^Vr@i#)Z1;cq$$xE;;GoXpL05(%+O+nIW93p`IyXJvYMnM)&KoTFf0tzc z(`ikR(1t?Lrb%`t>2|QRy1CJM6OU&rVwQ5`#8vwL1x#RoN@Cpq+rO!Op$2w0x66YV zM)$+#_AU}bLMorFZ0K1RNryn|(O?;{I0ZGI&oBe0IrB0Y8QUej`TC_{p&z`GqNHWJ zudJKQIyn8^V*Q-mEv>)e$F>O5o?yTnU{c)W_YQT1l;HC57~-F4(r3w?1uoJ z88!f1j>gI639Pr{-wy8K1a-h(Db?x&Z}&q)_Hc<5`Dg4XsKvsfK;abi=oFF(=J59VAVlP#K?J+*ZMiTVR_>VFG zj}BSxi0Quv88AHk1q#N8KvMtaBJ=Jt^AL1UR4dMZN8SH}Nz>>fs-&VG&VBsdPq6Y& zA4#=?tlf|Ac9vRwlWZG)xBoTbXgcaHTM1_?@I4(`K6tccjl|h{<5&kM5FH>Mhw#4k zJOpo1=mxxD91!y%34pz_S69ab3zthk2WAh-@v|QSyU^~FgL~oMcK_+L72U!i_>zS5 zoJVDsQ1X3s#-6G;oLA4GiwJS~edh`3_lRLy>EJ*Rqx2YF(?$F$5R9BE zcYY150Hw6tG*}spHP`vBCJip+`)*~GfnhdRvBm-I@QlJ7{THQY751uN2;6x`7Q9WX_JVFL4K1dpx^$0 zwd}c9tu=cGT(_7puw#WJ;BrL{eyOoUATcdDV(h5M%ycCNS>)PK33Udv>jE($Dns;Y zL-@8<#~t7-FmlR@5_u+|Q%QjSn8h%)(kl>IQM0C40jvP=KFJri13ANa41VjIJQ;d! zUibQIG<-WD zxO&vbpipx#uqQ--8bpsH&fau9rPVkQbe7h9GMs}jd1-Ej13pep4u7C7f8y?J>~%dF z@>BR+EPMNwGnL%mYZ<>= z-D`zcwkC0C)24fwGt-({&HyN24RLaolo_5|i4ZJUcW>`sfYPzG;-974d!Uyx0K?je zBgkbzW`579^CvkDr3^+2Zg#)(6Zh2~%5W@GuaFoR3z-u?G)h)5%`8SY(utb~e&Y^h zp26|ypq<@f1WmLL;{UdTD;VXFv=v-CqHFE*xLkB=G3`7a@ohS{(%$)u+jzV2G#5Ap zzF%%o3gqqwm2>h}ZGi7c;LqF3)o~5^Ak%2E2Ga*+KpiaG*7g~}0=={5h1*|%)T}5J zyi&O+vUsM~y986v;`MUrq^eBda{RpwWC`*~VD2-QM4&o>jyM@d$z!1`|Inz&-*euf zhfy^cgVyg}2(k=3UDyEn;@S?zC3EPLoVzVL2&Pe=18{^t)1lFEl+}y_CtC{a1zr>L z#%WH)77r_ik!6~L+#|Ny=IuifsLwLqbpL&|Dg zN$+}4U`e@BM#s56`8h!2nAfld{Pb9+=AX5Hu3MXhk6VT-c0sd#^a@DmH4Jn@vjQXO zlx2&rO}*oTNOYlt?`;baP&2{RT_{-W%0suQQQiGHNm4PUG!|JD!+uPYlTGt6M@FK( zd>lCyg1crJm65E}Uu~Tcca*~y-3Tfd`S-a}Z%}ofq6Cl`kGun)_t)!*EB|v&xmI1N zSH-J6Q+7?#fX=Z{b*5H)?lq)}qo|OXKVv^&zr66YPHfWPYeL=Rkwdf2VttgGUv*yw zbSd=JY2SVji2*uLOi11vm8Ba2QJ*mmW2&SJ)xwSb7T|ppmzPj+sr0Z-Gi{mY>5OT5 z?d-Ny4b3+8YL{>{I$J!Ok5^`!@!K4!D%*Z6k-x1{J4Wqqow&-w`chfF?b_Kl9t@-H#!*yeFXz>^hRO&fDbJrA0xcUwsD>;S>u=%ZHuv7=?ZkmFq~Yy;HQF>d3qKGOx9s8iq67GmVJ!3zXz!YL%*4ZZY5_^% z#B5r}F|2FsY}9p;D6}I(LliM`=!Uc~lZvE6lvzJu6-vWiJAZ6^@;x<#F+rO<^XuFu zSo@DuVj>Q>d19SDK(KD?(%=oC1PY{lH_b(J_J@D8z7<$B+tYIouyA4azFG!bS>WtF zHl8la^(?YFEfj~dMhdRS*@M|e0V2+niBZ{#AEI$-b8ujOg6`Lz_1`v}_s)R z+c)F!+CN;^LN(e=V?+~Vq$Y=qC|#mgsEI%j0(Dd9W%Ig(Sz+R$8cOLJbKh+YX659v7uL( z{o>^&8nKJG{TAXfXh5nU(IZdvQ2Ejs@_W+>rV~!JT-@VSu&~FJd7hcII&ZZ~-GQ*q zMrYGFT(jpM(!9j_4(57-*S`xJj|a*DtI199um|lWd#l$?x@$B}M+h#iYL9&!mJv%~ z(CUDZ1^%$`j*TKT_%v2kG#&S!5-#CD34TW|cVi%3FG=|}wjz?K$PWrRi;LUy)}`vD zt(gyL3`w)&7IEobx*u82x(6 zuEIepk^CN|V0O_-P^?Z@L0C}OE zVh6iC69~_3u)M>{bNXGOjJSS+qfno2{c=v3R;*Q)FwYc_OBZXTyF2&12BMc44M(4L zpq72b#KEYkXH`v-VDINUjKN}1Hww`OqomTX6E%u86-U>EiU<*1t zDGluAjb9BSKwHxDYvw#jj!Lx*X*$?9SgAvqAWKdwDQk&h797+*x%z5D_b`FQ>N#er zq_QsS5XaIu!A)Sg`c#*A5+Xno8-sq1?t114Dw2k)l`8t_DW&_THiTc{RW{ZyUFG^) z8xZ~4iy2dnu_E-I+X~R=F^UE?m5aeke4K9Jw?fJEE=`-6^da=WyW zAe!zZ5>2n+up_azvBw6W{5`P{|GP~sp@G7ri)ho;#f-^pGrO?5ekpKEUPF4RMltfo zY;+DUH1r9C3X&)GXC&ZDZtDPdCMQi39A{46w2e#=AvJet_qP<}CIT~Vil7ZAif$Iv z=9C37lvXCSPP?Mzt35`M{?qYV`U|;EzLFF)l+GhDW2Zn%GW1$mm)E6FCpQ3xK497N zpi$iAr{|*g@Dr@r+9+#&nl~S|1~^+fAN_6tH@C|}HHtdXtLfDR)Btp;ozhwZU9`aO z1nHw7n#OLoXekx-7gi?+pyRDb6gHxF)8J{k)zi}8%vcZeh9-lgtuf|+BFhX?<`f%( zj%f<-KV15xivq!K-ea~i$f1>7R+kQroL-BK;GS`37GyK zIr|77_E5TdT`X(9T3;ArMs9vm3rXuN|6P#Ek4<5DFvU5*a}IOxgUYV-OMG(fCbbN9 znba5XwuDw{5Dti4{JP8WyO5Zzxj9}yE4?QHJl_0c8h^)4jheWb;p(I9y5NG8;oljW z`Q%~1(oMHOEHnYPkYZBDbFZyv=>f4el)dUuYE)x4{!oHqoF_?sjr>yQ^EWT7%qcx5 zmuY$&w<8Ept3LSjeJ|ZDT_i^`bQL0Fc$Z4VeZv6AdD_Qu z7EizzdY`K?`wQcc{DvX~RIdAE68|AOKVytx#KoYA$aVK%kppC`J=ud$8#B|K{@EkS z7b=iiCCPe1l?}kvvtWb_`}`((@yk4s;!5q0&F1 zP`Qnn-7fFGC9V+zr$N5o={1DW~(B-woHjTE@Flpn)_aA#6a$53JW!cLtyWh+*F zN)Q*0byYJjE~krz4>;do=KSByrQH1);fRIAz z6d6Ad_S`_vvv%R#)20T>7gqtoA(9<8EBhcx`g|<=Fzl*A=&d4=xkz9Z7ikqVic9u~J^t*|q%cM}Pe;%Vv zQmj1%v>{&#DN;+Hwcx8q5Inww$7D|MY~v5tDXl!Z{)iWZcdHPG>Asnql!-il4w@4m ze1=_uHXr54sR)Trpg{Ly9WYPBV53y-{OU{fRKpe60=r@#@q9wvBF$f8Dm(v*U3F7& zERlnuyE8p{pLkAqxkh~hNmWEG#~{m0>Xd zWN!BWDnr@H*{xlrzla~Fp`r|xtQ+_;!~f}kG8=!nKFKZPSj-rSZK@FaFs;z5j&qiM zm~GpH53vaBY$euDW#*9H#%%KIx%(d9EH^892XPKV78z{{RVs0ZU71!ss1B9yTbdrM zG++KZh=o@wYZav|pE!km0M=o)EZ}-uyX`$d#T;Nz(a&rAl~rtMz4%-lJN4$KgN4GY zrTC(_7D-zyIQmsFUZ_r$(VZMh8N1mNVoU5ym&utg^eLt8;9v~uz!BwjQMLmh6b?HM z;YiE@aYOF7G;R~KsmL#06zQFSbjdqZw$0J9w#4R5Rd#pV+Zc|xL~5B4Z(+&RM#Ggw zL4ZbfLWKIvSxP|Lx0!cqmJg=_To;(Xj1AmkDR8u05-FP)}Z* zB($z2NL#w=?Slm@J?AU@wjbo_2dk=r<#Pxz{{8-=b-}e10pG9peY56h;t>tbP;Hn{ zOg1|FjzpG{MUNh^`L3;hordNT29fI^SIu#?6Zc=VLg&gPv;x5_8I zz0pdXY}YE((j0pHxS2a^kb|l4N?P|D)>zS2O-x3rwjZ;BtR+b_Y6{DYgPGHlo{xhu zfK9o@=c+i{?WcxVgc)OaKQeSCL|m+ftUbmMH6tuFu{h?jZoTkXuC+1y#^7h(A&M#; zIU=k25Nim6?cQU&Hn@TkEN8K|%Ee>x72+@yUDixUz^kCNvR zc9KTbeBfSas%&}Y&E-XQpmoLgC&Kal17$pyL-w}1OoHx}`=D6T-;YVRDiHB<={NN` zRcPA%(g@)A77MG!(qd-yhWW6(e|U;&jC?>JS<}^dFc>J&IUVjN zajA8Dwo2wkOlNPhJ8Ujzcmp~pPcyibwR46(3Os71eXsA>%lO5IDCVh1=iMx$AMFT@ zrU_nw9(Sczx^8CFLqMq+_C+bENcyycdnrky!y%^&!OLYJygn1++frV5G){Pc2hTXv zBdzqQ&htBb8a&zl(^PA%r>EdAr}yJZ075*W-pYpulWBOYcq&!|ZYPAIepUpL1c%2@ zFqc9(~5tv%)F9cafh%!2}H%KSnCxmOZ{nwZnI%mvI>&vwf3?xXp zb>Jgm*V=`%9;)RBy%(CV;Lsb|U<1KFBOUD=4tR1N07=`v;$S3Mc$92;H_iylr%t`V z{fiV4F+HlwsWT9*?N`so4HSr6Mz zilN~vFc)WiooZ*<*(nm&KW8b!G7FqhSD}xA}C#@56;o{*9r=QD_NYI{=?D$1V$+A z1kNce=1#oO^+4LU=`8R0bhVOngp9g~K7Bm+QkePs-7ID96wpE}CRq^CC1@(a6Ad}S z93L9RZ`C~mZ954|ytc7TUEdYC)D8QCb%&&>Bd_|nlyM&Kk8uE< zC5;Nbx7WQG z#H8|Am$_ag4Ia@rQ+QjQ;b_}Q&-BQ`IOuKYksCuoeZq<6?*pK@u1LgfCm9}hd^}0H z{f_upE}9})>Z{iA&nKC=l)fiTYxN<|b<#dOFNzt24Ih4L2NG}exRdlbsm2FonseaE zsQ?*<(gT(`Hq{>8o=l$e@drQ~^t60|_V#$FIPSQyWm@2KRp#8kWEvkNzM%*!A&5BJ zr_nb4ApD&ncEu1#oqlNy;W=}{XP?z<|I(;TlyISPqpr{>TfY0fP;9C6P-ALJ1+VR% z3ZY#YUY+rn5miy1!bdwzwpLQ`Ny&Nq*w3d=k}Y0i16)*HP5V1{Cyh*c`DpZx7*YPg zH_ex|wSTrLtV_5!WK^Eu7O|tmcO~W^@SCiCrm75eLIo={pu=5F?;C^E1VP(Y-mt&{ zY`I^J!Atm|AY`TQ_m{eN6Wia4Q#u*jMK)d#wo!R)E!*;BorrmrH2w7B?f(dkk+o~| zTG|~8M}zcG+qaFBx%T4yI7`E;g_b?Hb=P#fed0R=c(}b9yJsSD=d%*;kNlwV172Qd zs>3dWi<<{Rn_G!esc{D)hB3qV^eT$9kBHjBU;M?7$*M#@EMl&r$#kP9WOg!>3{PHx z+*WG2wFKChv0)maze3kL0S1NRPkq-U;wS6}D-F~GU*!q2V#+o%Jl_SOtu_bvlf(of z1K%NrG9)|#3BPA0x!s#aj!?8dd}?s%h(buLWTv*HYV<-TRrH7=p5rg)b4=L)v7f zrG9;l<3`>#8{Hae0V`d$+%$yp-Bx(bhf-B^sV1sE18=vCUoLfEz7vdyjJmeq>1AL!7f5kNu zMeKd3J~@2!Eza>Wq2s1nSGAsag=CXfjT2p8RsZXnRqDI1Cx(XTMv>xQsH>%%H-z=D zvQwFf+puxV*dbH(K?S};r}(2y5HaXfk42_sM=O(oNN?6{=#-*lD4IV7(4kw{b1P2t(7(?`({9Wr@|pJBwIcjX!fu z{mb}quXB5yAR&)o)L0}SJ8fG(+_BPp{k_n*@*{OOspG1x-H$BR_JpOo8`qkQo5q;- z{MK(&99#jvQ4nop^bX=d=gl&LFk(R6j8xCX6z*C9lf#P4_U4?(iK~epdTl_REpuC}oo!zJJ`UZC8kJ_RUZqKY=Z9fn@_RcM#?@9B&bB zND&pKp)%V1WX)TLEn4#FlXCpkWuV5#zrE@+>}YgI5Rv1UROwLA#`>Myj4O1Wnc>+Y zzZLE^_{#S3t*(X&B0Irfy)p^QM?X;eD?Y@FQfkLwa)vtg$<-V?%&;i1bi6rmm14(N z`rwLUjjk>b|&6xJ?p^wdDE8iPLC&(oz% z32N1*zsbvR2)#Kbeq{y_ilVF4XFMRI8~c$ zte(1Y#Y?xZ!>zq*ULlw&f0$bZG~^Ku3RoyfVoR+K4u^JTqJi)?cg&`=mM@IH1r{Nze=8=cja|E0neE%)G^tZrpjzb`3 zP72QTl+xnjimW=S#LvcA}`g(Wnt(rb@<^Kl?MgFQbL5CcL}&G|Z$YsB z^H;q_19rveM#>cJ^r-Yg8T!@gXUeQ(3p1@mh*+jOUmS`j9Fsb1ew8p3ZB&?9(uZ70nEQSm>QB$#8UV!zw!uNyvlA)Yx44}=mZtAC&fX8Dw zyZcJ3`B_mafd)s)<0aA`NaUKO*l+mzDi z0-we}n$Gek54=8T6(4jqxT@3{&?ja0&OWJypNYiP1dnscpm)&N4_lgGSEBhIMU4HN z)fC0~T!yI1ib@J(+K@BCyuTKA43jBfy%0t6;wRsl9`d)@1>$CfMF6*GBjc70Ffj=G zh7&L`SN#F~Kqjfs19iwG!%6$I%0bveHEVTiWLUbV+on^^sur z%$u-6den7CmgYrtqw@tr9;F!`*!dH^zb%DY_`tBBfGK_t{ z$M&z#wiE5dO+0m*;qqZ&Mv;aspbM$KqQ!qy_`!a|J>|=EuRNIVaDryva0%wKu(axVr?fx#UP`6PqEPhJ-}>%l~9t zJ;vV>M2uASxn!f&6EoX}j{S+Z+*%>xck2vU7C+Ex$nTpImPDAdDx~bdb{IX-H^sUJ zD3&TmIr8anc|0C<{7&>I_Rp~3z<&a$qlJg zWur0*Y&LnzrQUq}BSUMwx*fR19dDgJKfC(6hS4GF-u}x#*}b?X$4K)=)R$R?3|@Vl zq64mjc&&Kf9~Wcu(V~(D1U~ z;l=d7cdRz02GS6F&<-fXzz>`#;-!URuIz!j?x@!@)L9{tN&ShQVTQu!U!|;i@skZ< zeH={Pjo}6hw}^Ofd0XVHU*MzjTlX5}N4E+Wc(OXCG~Cftn)$c#FRKq;lv{ zdw%0Hf`ZhB>*6MAdRiOqW1&@Cd1y3%oY; z-wLngBXt4(!t7;s!OuYzuyQJwiFNJ$c`VCC{XS{a{F20&6 z0{WV68Wdx!fRSPcO&+Ru@jpR~1_jQvukV90CHwjNh>ffc^tBO#qI!R=2UMDnlsCny zaZxtls2JvEwxL@lAb;k*$0db*T=G32n6FmbldaHlC6KzEi*}mpV*u%iPTh~|@vA)Q z_Xv`1jFUvG(;lqD;ia|RYD2y{Ed8i$Ere~l#)iePe!VLxgjF)2zw=62Zw2Z+G#P&- z3~AwRA9WoT>z4?*z5&b(89`~}pk4SY2SI&60|!mh4!cAxSMC8!tWQdZ*u#2(Gb7NA z`z7~9v>hVW$6#yjq0ei@aXYG_h(-E)p%pBp$Xe`~?7$hqTq}L{WGZ{*=r1R;&0*h) zkJB4)&Cj^GF*%;Gb$G;p#QGkxtcHI}erjt~i_kr*JJ0+!r|C?8V`RY6U<~J@T?nOz z93N}u2|)in1oJJk&wR;rn7v>Lxp87e?AU2cxq<;Y6kIP8D-&)x9y%9=P0zg;Mg}({ zu$+iR=RkD)OD)!Q45&F`5xDc)x`Gl`C`KoVaY^}|RaN@h$;H1@KxszGks!&bz9qfw z^>eC}Om_qLyRDhQWqUK!!Is^foY)26g0IbN(iXmIQXufyXuM(JDQ7doF11JvP&~N< zNC5NHEFZi(vJ9k!unpQbf`)WQMG%y80!QqxUe{~;?IqtJd#khsT~^pnS~V{bpa*I< ziQuI2IY}jNP?^917gXw--yh|>CC8)nH-`)%P3%CeptvT)GGs6h^adxYF5<6<+Ui;X zY@f}G0_{V!OwJop*5fZkNFP_hN3m(|O~H#BN-GN*?myoY?$%HStazOa#S(vzbCdOZ zQW&cu%yqNNLw~=KwcfYLc|Pgb?Soh+R_c`7p=Hrigm0leQTLCRa5RE7O*!!++EQrN z1kVd|`d2y#{X47<0fP`#jBL-#^~Az5+faLSgrZaF9~EhCswP?H8=|PLi*u(^1RJI& zn_z)I+6tldp&fs@-LvL>*~x|=*Cc%;_LXq)qxYdU{nEO9k_`@*!lBcic zes?1#J#0=v(Bv)Ir)F*&U)2$_BgV1DNDf?Y7u4(ZTl|V3=TpJF29&9khx=I^3D`SA zOOOq&kyX+f>ohmbUQBUJO30gY@c(TW&vYbSSr=Eg1Ibmo>fGt&kjO!vOVU?&Sfnaq zWQA z(&MAz$uZX@Z-IEW*l8dDN<+~+{sb5qj$NqaHf;q4g`m*Wy8uiHE-e)-HT7>j>}2(oz)&v-h;-qu)2~mg?0^X3+u%amQ*k2FDqwH*h8+rxp*xWE>QiW zT3oLQty5Jn&R|{VyWz(5$=x4&*9XLc2Z{6h+ox=fVqd*8DE7#zfTVO$B&fZpCUfrJ z!)#F`$|rswFRK&MVK>fjhvm08jc2*`C!%-7uBt@72PlY9u+jHW@P zM`KW^M4V(AZG4xg@PyN!R8jckE}4-$rHk2xxn5Q>>2l!VH?!B5-f4U-3ukjdUsmYO z<*8g==*^k+I}fh-2L3VCw04m6#Iky2%Ox1}@{I)`J+z+bS{K-3dmdD(Mp7?1X&MzD zvmAe6_A4KHXhN_aju$%JgLP|Sl65b^?IitU?fjOCqT@RdjO|&$>w(Moo3)4`dUH8A z9RgKN(v8nd?^nH_@dzp3_ITM)!_GUA+p0RT&N5^9{I?H{7Dg`aL)-nM86|$uOHmvD z=s9czg6;=R%wO}tn8u7|pp{m4`BDnK!_j1cc#$5`8IFNWu|mAlWW=yR;U*iWaTaa- z?sli#@WnI2$JB{;J|He_OqjE2Q+p}w`bls@J9_l@nxs|=vh8n%@HdanF9yQAOv}6h zY(<^=>n(1(z*`JmoI?Jo1~qfy)r>d<4CXTU|cA2 z)jp5?u!;3-Pg@>67xv{-*(}&^JRwGZ3Vmg_1eyZFPjiwso6acUPFQ_i&mABUpdJ#Y ze{9;xSunr&dDE?fP@4Uxd}p1CPHcBA8pK>->0^tS0Y@3L+EOhDV^~|r* zh3?*kT`MU~fB@msV&ewBpPyH6(ppmlN2{HH0vO#W6gqB)A`&Rq*-j^4A+fL_q?FW~ zhR)cxbgzI~96#;7*gl)HQ^l9ZOWw(!mwQcq-Fft4)HIBRSlL8^g{k_!7$$q0=?dAg zAR1e6cxEPb{Bib)pTiKCt`yfK_4{q&#PWt4Gg^s^dryiofXhS8x|6__?eJa+=r~>F zHjVWH>vQ$*?Plrzp3B<58)%XgZ$)84=BSveK%@_pW#Zcuos&=eh34L$92Ko zGEJ!7Jtgd!!Bi9-RzMF?j=a9w7A;C&iCULD#ZJNXXE+NfMi5H?Jqfet!*dAv(pAr^WjkL_ zKANl{pm|=-@H{X*k4vhCnU#vhWl+n3>Fvo3454-xgguI)yq3e2YFDU8P}D(K zMR9|yScN)-Uz<9dyXKUyh4o~HX6t9DobHrK<32-%L<{^QfY6el?N{=YC~cv6={Lvy zO4_0nqfgCNZmLEK-LGZE(K>_=*su}-h-jCKHe|=l*#BT6u#VlW3>Q^hN|-NYKhhgx zKOoS7q?BVwc5#cu_y;BL>*rHe5#28Q$F}R<5ePkjWKF~MsxXl)YeEfvgh`%7Ad7PE z{jA5o<;W4)^G8kL4t6>#XrsTqHlYCZiR`y;TB0p^D`P_S=V5RvsQXP z1kUw!ESRf-zQs{2@Ze34Q|sX5Sd$pdWtVjsMLYJgze|GAz=5p4s8h+G84@r^lSIfD zeXh0q{Uo}H{^t>ed{&U%XeuUtT0@7hMxe8qS5gr7ndSQj#+H`Jj3sZMGmo}tuSPib z5=dU=4VoS34>@U3l*VNy){AL+imyMN^2k_snVn9o8H77=f^N#jYICo!cbt}pG>v2P zKgOVM@e^RKb!gkv=UpOU=jaE}{g_R*><~5#qqSlnkFa$;1@{^YI&ajo^?Dia6?diN zv5l#SSkI$4-hVqvG=UHJWww0J+k5#l&V|!(%b;Q(L|&p(6Q6U2!g^Z=i!!6(So`01Oda*b?E_z{J9C+`(c- z>Gmt8aZtt_ukykqqCj#vOf8KR<`%JH{QJ7m0otMaAe1LY{8oG0>jW9~oB4{#S)qJP z1x#WHjYs;78I3wlYK2RJZZz8f`q2KqBa^b8cs`gZs|lXgw20?|_sNFaRhv$kgdO}g zEtkJ;EU%hCA^)>z z>Cb2|RRQiC$Rksd2jyyXQROUp#Shz%S-p&o%-qmuu#8@ta;pk)oluvD1fG+iHaJS* z^}eUH_CM7$W6eYh5F(J>8nz!wgI>_pu$Ol}a@UyJ1XAwAD^WJX?e!85>&=Aw;vf(oJOcB0$Wp%9m$A|U&?xf|CXDU-k?i{EdE92kE_{Kla zgE6B=gl)wWtU%fs-^<>29m@vIB>SQjea0Kp@E!=ZBq)r%7L|p54PX!Pf zx9Y9anccCU8eVXo#)CQ;KlM<~Bu#QL0;8qqd+77DF<=oQ?)eboy4q_ODlK z&BfM5<|)gcR5y-Ngv^d;2e^F%qj{Vt(30~X^f4&iLFhh0qr~X-5fZ$PYd;wB?wdqY zZwjKuts|O5@FuB&lYqf(-C9j-+*3xWoko+OZMt>zACDE3>GIfzE&544)xisyH!^Os zEsB5JP^*;gQ3Y(+*ECJ%2bz^jjjR7K%;j0W4ql{OaP>51&kDHHO^Xi_lxF_u8;`}h z_8w0a(dZ(EMGSX7+6 zU1=0o&etu`TUX8>LCnk*kawLiD0L0&)QO* z*0x6T@xZmJQf5?Du8jic!`^ZHS&l_EH;Pdo@@H}6!=L5mjsw3IMlBkC1F(#vNA1?p zmXt_V#hWGP5!`UXFL_xrt8z(e6&!@_R^D-^Ui~pw_84$q) zSFDh}I#bvkbidk$OSxbG+b=bvT< z-!&~Qilp(&6(nE#GGq4Gz+NUa@A!28Z=nEaKtsj;B4>EbXHEUfz50)jrezu>1IWLtY#;9oM3V9_6(e?e zQ~>Ici^k5fSGiSmW+RBa6;Epp|GSU`KhIV3_T}bt(rnn$8OT0Cx2c-T(jZd&!40 z#^+@~8x^1VJqdi=djL2kBybNn-(heyB$)No8A#a;cf^7~pu2j7itAA#1SJhX)He31 z0gpGncr^JLvV(w&*+5gxr~xDeI>KAS@H=Q2AFBeG=!*=X<+8ChX@2NNz*N8t9(Cqu kXyQ&yqiJ(wW}y%N|2>)iuFVdQ&MBb@0BN!t!~g&Q literal 0 HcmV?d00001 From 66429754c83982828ac4db21f497bee52ee2279a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 16:30:11 -0600 Subject: [PATCH 08/14] refactor: Move core logic to a `FileStream` --- poetry.lock | 2 +- pyproject.toml | 1 + tap_csv/client.py | 100 +----------------------------------- tap_csv/file_stream.py | 113 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 99 deletions(-) create mode 100644 tap_csv/file_stream.py diff --git a/poetry.lock b/poetry.lock index 44acb4e..f8c5dde 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1402,4 +1402,4 @@ dropbox = ["dropboxdrivefs"] [metadata] lock-version = "2.0" python-versions = ">=3.8" -content-hash = "c218fd70889a2509ee65b9a3a85187112437dda863ae5249d0bbeb4bafc57bd1" +content-hash = "dc24ddf88fb5ceb48c0cc09fc9f8ee7482a5e277bd23452d046a635fe8251792" diff --git a/pyproject.toml b/pyproject.toml index a8cde72..dd72e0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ license = "Apache-2.0" python = ">=3.8" fsspec = "~=2024.6.1" singer-sdk = "~=0.40.0" +typing-extensions = { version = "~=4.12.2", python = "<3.12" } universal-pathlib = "~=0.2.3" # Extras diff --git a/tap_csv/client.py b/tap_csv/client.py index 44282c7..30cabaf 100644 --- a/tap_csv/client.py +++ b/tap_csv/client.py @@ -3,35 +3,17 @@ from __future__ import annotations import csv -import os import typing as t -from functools import cached_property -import fsspec -from singer_sdk import typing as th -from singer_sdk.streams import Stream +from .file_stream import FileStream if t.TYPE_CHECKING: from singer_sdk.helpers.types import Context -SDC_SOURCE_FILE_COLUMN = "_sdc_source_file" -SDC_SOURCE_LINENO_COLUMN = "_sdc_source_lineno" -SDC_SOURCE_FILE_MTIME_COLUMN = "_sdc_source_file_mtime" - -class CSVStream(Stream): +class CSVStream(FileStream): """Stream class for CSV streams.""" - file_paths: list[str] = [] # noqa: RUF012 - header: list[str] = [] # noqa: RUF012 - - def __init__(self, filesystem: str, *args, options: dict[str, t.Any], **kwargs): - """Init CSVStram.""" - # cache file_config so we dont need to go iterating the config list again later - self.file_config = kwargs.pop("file_config") - self.fs = fsspec.filesystem(filesystem, **options) - super().__init__(*args, **kwargs) - def get_records(self, context: Context | None) -> t.Iterable[dict]: """Return a generator of row-type dictionary objects. @@ -63,47 +45,6 @@ def get_records(self, context: Context | None) -> t.Iterable[dict]: yield dict(zip(self.header, row)) - def _get_recursive_file_paths(self, file_path: str) -> list: - file_paths = [] - - for dirpath, _, filenames in self.fs.walk(file_path): - for filename in filenames: - file_path = os.path.join(dirpath, filename) - if self.is_valid_filename(file_path): - file_paths.append(file_path) - - return file_paths - - def get_file_paths(self) -> list: - """Return a list of file paths to read. - - This tap accepts file names and directories so it will detect - directories and iterate files inside. - """ - # Cache file paths so we dont have to iterate multiple times - if self.file_paths: - return self.file_paths - - file_path = self.file_config["path"] - if not self.fs.exists(file_path): - raise Exception(f"File path does not exist {file_path}") - - file_paths = [] - if self.fs.isdir(file_path): - clean_file_path = os.path.normpath(file_path) + os.sep - file_paths = self._get_recursive_file_paths(clean_file_path) - - elif self.is_valid_filename(file_path): - file_paths.append(file_path) - - if not file_paths: - raise RuntimeError( - f"Stream '{self.name}' has no acceptable files. \ - See warning for more detail." - ) - self.file_paths = file_paths - return file_paths - def is_valid_filename(self, file_path: str) -> bool: """Return a boolean of whether the file includes CSV extension.""" is_valid = True @@ -129,40 +70,3 @@ def get_rows(self, file_path: str) -> t.Iterable[list]: ) with self.fs.open(file_path, mode="r", encoding=encoding) as f: yield from csv.reader(f, dialect="tap_dialect") - - @cached_property - def schema(self) -> dict: - """Return dictionary of record schema. - - Dynamically detect the json schema for the stream. - This is evaluated prior to any records being retrieved. - """ - properties: list[th.Property] = [] - self.primary_keys = self.file_config.get("keys", []) - - for file_path in self.get_file_paths(): - for header in self.get_rows(file_path): # noqa: B007 - break - break - - properties.extend(th.Property(column, th.StringType()) for column in header) - # If enabled, add file's metadata to output - if self.config.get("add_metadata_columns", False): - header = [ - SDC_SOURCE_FILE_COLUMN, - SDC_SOURCE_FILE_MTIME_COLUMN, - SDC_SOURCE_LINENO_COLUMN, - *header, - ] - - properties.extend( - ( - th.Property(SDC_SOURCE_FILE_COLUMN, th.StringType), - th.Property(SDC_SOURCE_FILE_MTIME_COLUMN, th.DateTimeType), - th.Property(SDC_SOURCE_LINENO_COLUMN, th.IntegerType), - ) - ) - # Cache header for future use - self.header = header - - return th.PropertiesList(*properties).to_dict() diff --git a/tap_csv/file_stream.py b/tap_csv/file_stream.py new file mode 100644 index 0000000..94731d7 --- /dev/null +++ b/tap_csv/file_stream.py @@ -0,0 +1,113 @@ +"""Stream class for file-based streams.""" + +from __future__ import annotations + +import abc +import os +import typing as t +from functools import cached_property + +import fsspec +from singer_sdk import typing as th +from singer_sdk.streams import Stream + +SDC_SOURCE_FILE_COLUMN = "_sdc_source_file" +SDC_SOURCE_LINENO_COLUMN = "_sdc_source_lineno" +SDC_SOURCE_FILE_MTIME_COLUMN = "_sdc_source_file_mtime" + + +class FileStream(Stream, metaclass=abc.ABCMeta): + """Abstract class for file streams.""" + + file_paths: list[str] = [] # noqa: RUF012 + header: list[str] = [] # noqa: RUF012 + + def __init__(self, filesystem: str, *args, options: dict[str, t.Any], **kwargs): + """Init CSVStram.""" + # cache file_config so we dont need to go iterating the config list again later + self.file_config = kwargs.pop("file_config") + self.fs = fsspec.filesystem(filesystem, **options) + super().__init__(*args, **kwargs) + + def _get_recursive_file_paths(self, file_path: str) -> list: + file_paths = [] + + for dirpath, _, filenames in self.fs.walk(file_path): + for filename in filenames: + file_path = os.path.join(dirpath, filename) + if self.is_valid_filename(file_path): + file_paths.append(file_path) + + return file_paths + + def get_file_paths(self) -> list: + """Return a list of file paths to read. + + This tap accepts file names and directories so it will detect + directories and iterate files inside. + """ + # Cache file paths so we dont have to iterate multiple times + if self.file_paths: + return self.file_paths + + file_path = self.file_config["path"] + if not self.fs.exists(file_path): + raise Exception(f"File path does not exist {file_path}") + + file_paths = [] + if self.fs.isdir(file_path): + clean_file_path = os.path.normpath(file_path) + os.sep + file_paths = self._get_recursive_file_paths(clean_file_path) + + elif self.is_valid_filename(file_path): + file_paths.append(file_path) + + if not file_paths: + raise RuntimeError( + f"Stream '{self.name}' has no acceptable files. \ + See warning for more detail." + ) + self.file_paths = file_paths + return file_paths + + @abc.abstractmethod + def is_valid_filename(self, file_path: str) -> bool: + """Return a boolean of whether the file name is valid for the format.""" + ... + + @cached_property + def schema(self) -> dict: + """Return dictionary of record schema. + + Dynamically detect the json schema for the stream. + This is evaluated prior to any records being retrieved. + """ + properties: list[th.Property] = [] + self.primary_keys = self.file_config.get("keys", []) + + for file_path in self.get_file_paths(): + for header in self.get_rows(file_path): # noqa: B007 + break + break + + properties.extend(th.Property(column, th.StringType()) for column in header) + # If enabled, add file's metadata to output + if self.config.get("add_metadata_columns", False): + header = [ + SDC_SOURCE_FILE_COLUMN, + SDC_SOURCE_FILE_MTIME_COLUMN, + SDC_SOURCE_LINENO_COLUMN, + *header, + ] + + properties.extend( + ( + th.Property(SDC_SOURCE_FILE_COLUMN, th.StringType), + th.Property(SDC_SOURCE_FILE_MTIME_COLUMN, th.DateTimeType), + th.Property(SDC_SOURCE_LINENO_COLUMN, th.IntegerType), + ) + ) + # Cache header for future use + self.header = header + + return th.PropertiesList(*properties).to_dict() From c46b1658e3cfd8da23716f1149e7f12860a20fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 17:47:58 -0600 Subject: [PATCH 09/14] refactor: Move even more of the core logic to `FileStream` --- .pre-commit-config.yaml | 2 +- pyproject.toml | 34 ++++++++----- tap_csv/client.py | 72 ++++++++++++++++++++++++--- tap_csv/file_stream.py | 107 +++++++++++++++++++++++----------------- tap_csv/tap.py | 14 +++--- 5 files changed, 157 insertions(+), 72 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71b1d90..2d0933f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: )$ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.3 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pyproject.toml b/pyproject.toml index dd72e0c..182797f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,18 +49,28 @@ ignore = [ "D213", ] select = [ - "F", - "A", - "B", - "W", - "D", - "COM", - "I", - # "PTH", - "PERF", - "RUF", - "TCH", - "UP", + "F", # Pyflakes + "E", # pycodestyle (errors) + "W", # pycodestyle (warnings) + "D", # pydocstyle + "UP", # pyupgrade + "I", # isort + "B", # flake8-bugbear + "A", # flake8-builtins + "COM", # flake8-commas + "EM", # flake8-errmsg + "LOG", # flake8-logging + "G", # flake8-logging-format + "PIE", # flake8-pie + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SIM", # flake8-simplify + "TCH", # flake8-type-checking + "ERA", # eradicate + "ARG", # flake8-unused-arguments + "PERF", # Perflint + "RUF", # Ruff-specific rules ] [tool.ruff.lint.isort] diff --git a/tap_csv/client.py b/tap_csv/client.py index 30cabaf..e1bc0e5 100644 --- a/tap_csv/client.py +++ b/tap_csv/client.py @@ -3,18 +3,40 @@ from __future__ import annotations import csv +import sys import typing as t +from functools import cached_property + +from singer_sdk import typing as th from .file_stream import FileStream +if sys.version_info < (3, 12): + from typing_extensions import override +else: + from typing import override + if t.TYPE_CHECKING: from singer_sdk.helpers.types import Context +SDC_SOURCE_FILE_COLUMN = "_sdc_source_file" +SDC_SOURCE_LINENO_COLUMN = "_sdc_source_lineno" +SDC_SOURCE_FILE_MTIME_COLUMN = "_sdc_source_file_mtime" + class CSVStream(FileStream): """Stream class for CSV streams.""" - def get_records(self, context: Context | None) -> t.Iterable[dict]: + def __init__(self, *args: t.Any, **kwargs: t.Any): + """Initialize CSVStream.""" + super().__init__(*args, **kwargs) + + @cached_property + def primary_keys(self) -> list[str]: + """Return the primary keys for the stream.""" + return self.file_config.get("keys", []) + + def get_records(self, context: Context | None) -> t.Iterable[dict]: # noqa: ARG002 """Return a generator of row-type dictionary objects. The optional `context` argument is used to identify a specific slice of the @@ -27,7 +49,8 @@ def get_records(self, context: Context | None) -> t.Iterable[dict]: file_last_modified = self.fs.modified(file_path) except NotImplementedError: self.logger.warning( - "Filesystem implementation for %s does not support modified time, skipping", + "Filesystem implementation for %s does not support modified time, " + "skipping", self.fs.protocol, ) file_last_modified = None @@ -40,22 +63,59 @@ def get_records(self, context: Context | None) -> t.Iterable[dict]: if not file_lineno: continue - if self.config.get("add_metadata_columns", False): + if self.include_metadata_columns: row = [file_path, file_last_modified, file_lineno, *row] - yield dict(zip(self.header, row)) + yield dict(zip(self.get_all_field_names(), row)) + + @cached_property + def metadata_fields(self) -> tuple[str, ...]: + """Generate metadata columns names.""" + return ( + SDC_SOURCE_FILE_COLUMN, + SDC_SOURCE_FILE_MTIME_COLUMN, + SDC_SOURCE_LINENO_COLUMN, + ) + + def get_metadata_columns_schemas(self) -> t.Generator[tuple[str, dict], None, None]: + """Get schema for metadata columns.""" + yield SDC_SOURCE_FILE_COLUMN, {"type": "string"} + yield ( + SDC_SOURCE_FILE_MTIME_COLUMN, + {"type": ["string", "null"], "format": "date-time"}, + ) + yield SDC_SOURCE_LINENO_COLUMN, {"type": "integer"} + + @override + @cached_property + def field_names(self) -> list[str]: + """Return a sequence of field names for the stream.""" + for file_path in self.get_file_paths(): + for row in self.get_rows(file_path): + return row + + return [] + + @override + def get_schema(self) -> dict: + """Return the schema for a particular file stream.""" + props = [th.Property(col, th.StringType) for col in self.field_names] + return th.PropertiesList(*props).to_dict() + @override def is_valid_filename(self, file_path: str) -> bool: """Return a boolean of whether the file includes CSV extension.""" is_valid = True if file_path[-4:] != ".csv": is_valid = False - self.logger.warning(f"Skipping non-csv file '{file_path}'") self.logger.warning( - "Please provide a CSV file that ends with '.csv'; e.g. 'users.csv'" + "Skipping non-csv file '%s', please provide a CSV file that ends with " + "'.csv'; e.g. 'users.csv'", + file_path, ) return is_valid + @override def get_rows(self, file_path: str) -> t.Iterable[list]: """Return a generator of the rows in a particular CSV file.""" encoding = self.file_config.get("encoding", None) diff --git a/tap_csv/file_stream.py b/tap_csv/file_stream.py index 94731d7..e6e465e 100644 --- a/tap_csv/file_stream.py +++ b/tap_csv/file_stream.py @@ -8,25 +8,19 @@ from functools import cached_property import fsspec -from singer_sdk import typing as th from singer_sdk.streams import Stream -SDC_SOURCE_FILE_COLUMN = "_sdc_source_file" -SDC_SOURCE_LINENO_COLUMN = "_sdc_source_lineno" -SDC_SOURCE_FILE_MTIME_COLUMN = "_sdc_source_file_mtime" - class FileStream(Stream, metaclass=abc.ABCMeta): """Abstract class for file streams.""" - file_paths: list[str] = [] # noqa: RUF012 - header: list[str] = [] # noqa: RUF012 - def __init__(self, filesystem: str, *args, options: dict[str, t.Any], **kwargs): """Init CSVStram.""" # cache file_config so we dont need to go iterating the config list again later self.file_config = kwargs.pop("file_config") - self.fs = fsspec.filesystem(filesystem, **options) + self.fs: fsspec.AbstractFileSystem = fsspec.filesystem(filesystem, **options) + self._file_paths: list[str] = [] + super().__init__(*args, **kwargs) def _get_recursive_file_paths(self, file_path: str) -> list: @@ -40,19 +34,20 @@ def _get_recursive_file_paths(self, file_path: str) -> list: return file_paths - def get_file_paths(self) -> list: + def get_file_paths(self) -> list[str]: """Return a list of file paths to read. This tap accepts file names and directories so it will detect directories and iterate files inside. """ # Cache file paths so we dont have to iterate multiple times - if self.file_paths: - return self.file_paths + if self._file_paths: + return self._file_paths file_path = self.file_config["path"] if not self.fs.exists(file_path): - raise Exception(f"File path does not exist {file_path}") + errmsg = f"File path does not exist {file_path}" + raise Exception(errmsg) file_paths = [] if self.fs.isdir(file_path): @@ -63,18 +58,59 @@ def get_file_paths(self) -> list: file_paths.append(file_path) if not file_paths: - raise RuntimeError( - f"Stream '{self.name}' has no acceptable files. \ - See warning for more detail." - ) - self.file_paths = file_paths - return file_paths + msg = f"Stream '{self.name}' has no acceptable files" + raise RuntimeError(msg) + + self._file_paths = file_paths + + return self._file_paths + + def get_all_field_names(self) -> list[str]: + """Return a set of all field names, including metadata columns. + + If metadata columns are enabled, they will be **prepended** to the list. + """ + fields = list(self.field_names) + if self.include_metadata_columns: + fields = [*self.metadata_fields, *fields] + + return fields + + @cached_property + def include_metadata_columns(self) -> bool: + """Return a boolean of whether to include metadata columns.""" + return self.config.get("add_metadata_columns", False) + + @property + def metadata_fields(self) -> t.Iterable[str]: + """Get an iterable of metadata columns names.""" + return [] + + def get_metadata_columns_schemas(self) -> t.Iterable[tuple[str, dict]]: + """Get an iterable of metadata columns names and schemata.""" + return [] + + @property + @abc.abstractmethod + def field_names(self) -> t.Sequence[str]: + """A sequence of field names for the stream.""" + ... + + @abc.abstractmethod + def get_schema(self) -> dict: + """Return the schema for a particular file stream.""" + ... @abc.abstractmethod def is_valid_filename(self, file_path: str) -> bool: """Return a boolean of whether the file name is valid for the format.""" ... + @abc.abstractmethod + def get_rows(self, file_path: str) -> t.Iterable[list]: + """Return a generator of the rows in a particular file.""" + ... + @cached_property def schema(self) -> dict: """Return dictionary of record schema. @@ -82,32 +118,11 @@ def schema(self) -> dict: Dynamically detect the json schema for the stream. This is evaluated prior to any records being retrieved. """ - properties: list[th.Property] = [] - self.primary_keys = self.file_config.get("keys", []) - - for file_path in self.get_file_paths(): - for header in self.get_rows(file_path): # noqa: B007 - break - break + _schema = self.get_schema() - properties.extend(th.Property(column, th.StringType()) for column in header) # If enabled, add file's metadata to output - if self.config.get("add_metadata_columns", False): - header = [ - SDC_SOURCE_FILE_COLUMN, - SDC_SOURCE_FILE_MTIME_COLUMN, - SDC_SOURCE_LINENO_COLUMN, - *header, - ] - - properties.extend( - ( - th.Property(SDC_SOURCE_FILE_COLUMN, th.StringType), - th.Property(SDC_SOURCE_FILE_MTIME_COLUMN, th.DateTimeType), - th.Property(SDC_SOURCE_LINENO_COLUMN, th.IntegerType), - ) - ) - # Cache header for future use - self.header = header - - return th.PropertiesList(*properties).to_dict() + if self.include_metadata_columns: + metadata_schema = self.get_metadata_columns_schemas() + _schema["properties"].update(dict(metadata_schema)) + + return _schema diff --git a/tap_csv/tap.py b/tap_csv/tap.py index fe3f499..8cc70be 100644 --- a/tap_csv/tap.py +++ b/tap_csv/tap.py @@ -95,7 +95,9 @@ class TapCSV(Tap): "org", th.StringType, required=True, - description="GitHub organization or user where the repository is located", + description=( + "GitHub organization or user where the repository is located" + ), ), th.Property( "repo", @@ -170,7 +172,7 @@ def get_file_configs(self) -> list[dict]: with open(csv_files_definition) as f: csv_files = json.load(f) else: - self.logger.error(f"tap-csv: '{csv_files_definition}' file not found") + self.logger.error("tap-csv: '%s' file not found", csv_files_definition) exit(1) if not csv_files: self.logger.error("No CSV file definitions found.") @@ -182,11 +184,9 @@ def discover_streams(self) -> list[Stream]: filesystem = self.config["filesystem"] if filesystem != "local" and filesystem not in self.config: - error_message = f"Missing filesystem options for {filesystem}" - raise ConfigValidationError( - "Misconfigured filesystem", - errors=[error_message], - ) + msg = "Misconfigured filesystem" + errors = [f"Missing filesystem options for {filesystem}"] + raise ConfigValidationError(msg, errors=errors) return [ CSVStream( From 1d3b8c8980b7b3fe6d7f8bc9ff0988c94362ff21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 17:48:44 -0600 Subject: [PATCH 10/14] Move tests out of package --- tap_csv/tests/test_core.py | 92 ------------------- {tap_csv/tests => tests}/__init__.py | 0 {tap_csv/tests => tests}/data/alphabet.csv | 0 .../data/alphabet_encoding.csv | 0 .../data/subfolder1/alphabet.csv | 0 .../data/subfolder1/subfolder2/alphabet.csv | 0 {tap_csv/tests => tests}/test_client.py | 0 tests/test_core.py | 74 +++++++++++++++ 8 files changed, 74 insertions(+), 92 deletions(-) delete mode 100644 tap_csv/tests/test_core.py rename {tap_csv/tests => tests}/__init__.py (100%) rename {tap_csv/tests => tests}/data/alphabet.csv (100%) rename {tap_csv/tests => tests}/data/alphabet_encoding.csv (100%) rename {tap_csv/tests => tests}/data/subfolder1/alphabet.csv (100%) rename {tap_csv/tests => tests}/data/subfolder1/subfolder2/alphabet.csv (100%) rename {tap_csv/tests => tests}/test_client.py (100%) create mode 100644 tests/test_core.py diff --git a/tap_csv/tests/test_core.py b/tap_csv/tests/test_core.py deleted file mode 100644 index cdf5c02..0000000 --- a/tap_csv/tests/test_core.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Tests standard tap features using the built-in SDK tests library.""" - -from __future__ import annotations - -import os - -from singer_sdk.testing import get_standard_tap_tests - -from tap_csv.tap import TapCSV - - -# Run standard built-in tap tests from the SDK: -def test_standard_tap_tests(): - """Run standard tap tests from the SDK.""" - test_data_dir = os.path.dirname(os.path.abspath(__file__)) - SAMPLE_CONFIG = { - "files": [ - { - "entity": "test", - "path": f"{test_data_dir}/data/alphabet.csv", - "keys": [], - } - ] - } - tests = get_standard_tap_tests(TapCSV, config=SAMPLE_CONFIG) - for test in tests: - test() - - -# Run standard built-in tap tests from the SDK, with different encoding: -def test_standard_tap_tests_encoding(): - """Run standard built-in tap tests from the SDK, with different encoding.""" - test_data_dir = os.path.dirname(os.path.abspath(__file__)) - SAMPLE_CONFIG = { - "files": [ - { - "entity": "test", - "path": f"{test_data_dir}/data/alphabet_encoding.csv", - "keys": [], - "encoding": "latin1", - } - ] - } - tests = get_standard_tap_tests(TapCSV, config=SAMPLE_CONFIG) - for test in tests: - test() - - -# Run standard built-in tap tests from the SDK, with different CSV dialect settings: -def test_standard_tap_tests_csv_dialect(): - """Run standard built-in tap tests from the SDK. - - With different CSV dialect settings. - """ - test_data_dir = os.path.dirname(os.path.abspath(__file__)) - SAMPLE_CONFIG = { - "files": [ - { - "entity": "test", - "path": f"{test_data_dir}/data/alphabet_encoding.csv", - "keys": [], - "delimiter": ",", - "doublequote": True, - "escapechar": "^", - "quotechar": '"', - "skipinitialspace": True, - "strict": True, - } - ] - } - tests = get_standard_tap_tests(TapCSV, config=SAMPLE_CONFIG) - for test in tests: - test() - - -# Run standard built-in tap tests from the SDK, with metadata columns included: -def test_standard_tap_tests_metadata_cols(): - """Run standard tap tests from the SDK, with metadata columns included.""" - test_data_dir = os.path.dirname(os.path.abspath(__file__)) - SAMPLE_CONFIG = { - "add_metadata_columns": True, - "files": [ - { - "entity": "test", - "path": f"{test_data_dir}/data/alphabet.csv", - "keys": [], - } - ], - } - tests = get_standard_tap_tests(TapCSV, config=SAMPLE_CONFIG) - for test in tests: - test() diff --git a/tap_csv/tests/__init__.py b/tests/__init__.py similarity index 100% rename from tap_csv/tests/__init__.py rename to tests/__init__.py diff --git a/tap_csv/tests/data/alphabet.csv b/tests/data/alphabet.csv similarity index 100% rename from tap_csv/tests/data/alphabet.csv rename to tests/data/alphabet.csv diff --git a/tap_csv/tests/data/alphabet_encoding.csv b/tests/data/alphabet_encoding.csv similarity index 100% rename from tap_csv/tests/data/alphabet_encoding.csv rename to tests/data/alphabet_encoding.csv diff --git a/tap_csv/tests/data/subfolder1/alphabet.csv b/tests/data/subfolder1/alphabet.csv similarity index 100% rename from tap_csv/tests/data/subfolder1/alphabet.csv rename to tests/data/subfolder1/alphabet.csv diff --git a/tap_csv/tests/data/subfolder1/subfolder2/alphabet.csv b/tests/data/subfolder1/subfolder2/alphabet.csv similarity index 100% rename from tap_csv/tests/data/subfolder1/subfolder2/alphabet.csv rename to tests/data/subfolder1/subfolder2/alphabet.csv diff --git a/tap_csv/tests/test_client.py b/tests/test_client.py similarity index 100% rename from tap_csv/tests/test_client.py rename to tests/test_client.py diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..08f8d0b --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,74 @@ +"""Tests standard tap features using the built-in SDK tests library.""" + +from __future__ import annotations + +import os + +from singer_sdk.testing import get_tap_test_class + +from tap_csv.tap import TapCSV + +TEST_DATA_DIR = os.path.dirname(os.path.abspath(__file__)) + +TestTapCSV = get_tap_test_class( + TapCSV, + config={ + "files": [ + { + "entity": "test", + "path": f"{TEST_DATA_DIR}/data/alphabet.csv", + "keys": [], + }, + ], + }, +) + + +TestTapCSVEncoding = get_tap_test_class( + TapCSV, + config={ + "files": [ + { + "entity": "test", + "path": f"{TEST_DATA_DIR}/data/alphabet_encoding.csv", + "keys": [], + "encoding": "latin1", + }, + ], + }, +) + + +TestCSVDialect = get_tap_test_class( + TapCSV, + config={ + "files": [ + { + "entity": "test", + "path": f"{TEST_DATA_DIR}/data/alphabet_encoding.csv", + "keys": [], + "delimiter": ",", + "doublequote": True, + "escapechar": "^", + "quotechar": '"', + "skipinitialspace": True, + "strict": True, + }, + ], + }, +) + + +TestTapCSVMetadataCols = get_tap_test_class( + TapCSV, + config={ + "add_metadata_columns": True, + "files": [ + { + "entity": "test", + "path": f"{TEST_DATA_DIR}/data/alphabet.csv", + "keys": [], + }, + ], + }, +) From 0e075b10c2403fd90564db1ab19e2db4e5d56e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 17:50:25 -0600 Subject: [PATCH 11/14] Raise a more specific exception --- tap_csv/file_stream.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tap_csv/file_stream.py b/tap_csv/file_stream.py index e6e465e..4e81510 100644 --- a/tap_csv/file_stream.py +++ b/tap_csv/file_stream.py @@ -11,6 +11,10 @@ from singer_sdk.streams import Stream +class FileStreamError(Exception): + """Exception for file stream errors.""" + + class FileStream(Stream, metaclass=abc.ABCMeta): """Abstract class for file streams.""" @@ -47,7 +51,7 @@ def get_file_paths(self) -> list[str]: file_path = self.file_config["path"] if not self.fs.exists(file_path): errmsg = f"File path does not exist {file_path}" - raise Exception(errmsg) + raise FileStreamError(errmsg) file_paths = [] if self.fs.isdir(file_path): @@ -59,7 +63,7 @@ def get_file_paths(self) -> list[str]: if not file_paths: msg = f"Stream '{self.name}' has no acceptable files" - raise RuntimeError(msg) + raise FileStreamError(msg) self._file_paths = file_paths From a5ef92ed8f324a1f8b8ecaabac35e839f14b7fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 17:51:57 -0600 Subject: [PATCH 12/14] Make mypy happy --- tap_csv/client.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tap_csv/client.py b/tap_csv/client.py index e1bc0e5..ece4fbc 100644 --- a/tap_csv/client.py +++ b/tap_csv/client.py @@ -32,7 +32,7 @@ def __init__(self, *args: t.Any, **kwargs: t.Any): super().__init__(*args, **kwargs) @cached_property - def primary_keys(self) -> list[str]: + def primary_keys(self) -> t.Sequence[str] | None: """Return the primary keys for the stream.""" return self.file_config.get("keys", []) diff --git a/tox.ini b/tox.ini index 4694ab8..20d7f77 100644 --- a/tox.ini +++ b/tox.ini @@ -32,4 +32,4 @@ commands = poetry install -v poetry run ruff check --diff tap_csv/ poetry run ruff format --check tap_csv - poetry run mypy tap_csv --exclude='tap_csv/tests' --ignore-missing-imports + poetry run mypy . --exclude='tests' --ignore-missing-imports From 2f45921822cbadcc37d099b5947b2f2218f46f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 17:57:14 -0600 Subject: [PATCH 13/14] Add config examples to readme --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/README.md b/README.md index 9d598e1..67f1040 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,33 @@ Optionally, the files definition can be provided by an external json file: | github.username | False | None | GitHub username | | github.token | False | None | GitHub token | +
Example configuration +

+ +```json +{ + "add_metadata_columns": true, + "filesystem": "github", + "github": { + "org": "MeltanoLabs", + "repo": "tap-csv" + }, + "files": [ + { + "entity": "alphabet", + "path": "tap_csv/tests/data/alphabet.csv", + "keys": [ + "col1" + ] + } + ] +} +``` + +

+
+ + #### Dropbox | Setting | Required | Default | Description | @@ -123,6 +150,31 @@ The token needs the `files.content.read` scope: [![Dropbox scopes](img/dropbox_scopes.png)](https://www.dropbox.com/developers/apps) +
Example configuration +

+ +```json +{ + "add_metadata_columns": true, + "filesystem": "dropbox", + "dropbox": { + "token": "...." + }, + "files": [ + { + "entity": "alphabet", + "path": "/alphabet.csv", + "keys": [ + "col1" + ] + } + ] +} +``` + +

+
+ ### Built-in Singer SDK settings The following settings are supported by the Singer SDK and are automatically handled by the tap: From 09d3256745906cf739c3bc0ebb47f8dd01157768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 5 Sep 2024 20:17:25 -0600 Subject: [PATCH 14/14] Move FS configs to their own module --- tap_csv/filesystem_config.py | 87 +++++++++++++++++++++++++++++++++++ tap_csv/tap.py | 88 ++---------------------------------- tests/test_client.py | 6 +-- 3 files changed, 95 insertions(+), 86 deletions(-) create mode 100644 tap_csv/filesystem_config.py diff --git a/tap_csv/filesystem_config.py b/tap_csv/filesystem_config.py new file mode 100644 index 0000000..c522b86 --- /dev/null +++ b/tap_csv/filesystem_config.py @@ -0,0 +1,87 @@ +"""JSON Schema for each filesystem configuration.""" + +from __future__ import annotations + +from singer_sdk import typing as th # JSON schema typing helpers + +FTP = th.Property( + "ftp", + th.ObjectType( + th.Property( + "host", + th.StringType, + required=True, + description="FTP server host", + ), + th.Property( + "port", + th.IntegerType, + default=21, + description="FTP server port", + ), + th.Property( + "username", + th.StringType, + description="FTP username", + ), + th.Property( + "password", + th.StringType, + secret=True, + description="FTP password", + ), + th.Property( + "encoding", + th.StringType, + default="utf-8", + description="FTP server encoding", + ), + ), + description="FTP connection settings", +) + +GITHUB = th.Property( + "github", + th.ObjectType( + th.Property( + "org", + th.StringType, + required=True, + description=("GitHub organization or user where the repository is located"), + ), + th.Property( + "repo", + th.StringType, + required=True, + description="GitHub repository", + ), + th.Property( + "username", + th.StringType, + required=False, + description="GitHub username", + ), + th.Property( + "token", + th.StringType, + required=False, + secret=True, + description="GitHub token", + ), + ), + description="GitHub connection settings", +) + +DROPBOX = th.Property( + "dropbox", + th.ObjectType( + th.Property( + "token", + th.StringType, + secret=True, + required=True, + description="Dropbox token", + ), + ), + description="Dropbox connection settings", +) diff --git a/tap_csv/tap.py b/tap_csv/tap.py index 8cc70be..43abb44 100644 --- a/tap_csv/tap.py +++ b/tap_csv/tap.py @@ -11,7 +11,7 @@ from singer_sdk.helpers._classproperty import classproperty from singer_sdk.helpers.capabilities import TapCapabilities -from tap_csv.client import CSVStream +from . import client, filesystem_config class TapCSV(Tap): @@ -53,87 +53,9 @@ class TapCSV(Tap): "dropbox", ], ), - th.Property( - "ftp", - th.ObjectType( - th.Property( - "host", - th.StringType, - required=True, - description="FTP server host", - ), - th.Property( - "port", - th.IntegerType, - default=21, - description="FTP server port", - ), - th.Property( - "username", - th.StringType, - description="FTP username", - ), - th.Property( - "password", - th.StringType, - secret=True, - description="FTP password", - ), - th.Property( - "encoding", - th.StringType, - default="utf-8", - description="FTP server encoding", - ), - ), - description="FTP connection settings", - ), - th.Property( - "github", - th.ObjectType( - th.Property( - "org", - th.StringType, - required=True, - description=( - "GitHub organization or user where the repository is located" - ), - ), - th.Property( - "repo", - th.StringType, - required=True, - description="GitHub repository", - ), - th.Property( - "username", - th.StringType, - required=False, - description="GitHub username", - ), - th.Property( - "token", - th.StringType, - required=False, - secret=True, - description="GitHub token", - ), - ), - description="GitHub connection settings", - ), - th.Property( - "dropbox", - th.ObjectType( - th.Property( - "token", - th.StringType, - secret=True, - required=True, - description="Dropbox token", - ), - ), - description="Dropbox connection settings", - ), + filesystem_config.FTP, + filesystem_config.GITHUB, + filesystem_config.DROPBOX, th.Property( "csv_files_definition", th.StringType, @@ -189,7 +111,7 @@ def discover_streams(self) -> list[Stream]: raise ConfigValidationError(msg, errors=errors) return [ - CSVStream( + client.CSVStream( tap=self, name=file_config.get("entity"), file_config=file_config, diff --git a/tests/test_client.py b/tests/test_client.py index e14326e..11b80a7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,7 +4,7 @@ import os -from tap_csv.tap import CSVStream, TapCSV +from tap_csv import client, tap def test_get_file_paths_recursively(): @@ -21,8 +21,8 @@ def test_get_file_paths_recursively(): ] } - stream = CSVStream( - tap=TapCSV(config=SAMPLE_CONFIG, catalog={}, state={}), + stream = client.CSVStream( + tap=tap.TapCSV(config=SAMPLE_CONFIG, catalog={}, state={}), name="test_recursive", file_config=SAMPLE_CONFIG.get("files")[0], filesystem="local",