From 422a3859f0c278787fc033933d59a17e97a8b7c6 Mon Sep 17 00:00:00 2001 From: Steven Pawley Date: Sat, 7 Sep 2024 23:35:04 -0600 Subject: [PATCH] use pyproject.toml --- .github/workflows/publish-quarto.yml | 83 +- .github/workflows/tests.yml | 99 +- .gitignore | 31 +- .pre-commit-config.yaml | 32 +- .python-version | 2 +- LICENSE | 1348 ++--- README.md | 866 +-- .../geoprocessing/execute-results/html.json | 22 +- _freeze/docs/guide/execute-results/html.json | 16 + .../guide/figure-html/cell-5-output-1.png | Bin 0 -> 613660 bytes .../guide/figure-html/cell-8-output-1.png | Bin 0 -> 552239 bytes .../installation/execute-results/html.json | 22 +- .../docs/landcover/execute-results/html.json | 30 +- .../execute-results/html.json | 30 +- .../docs/plotting/execute-results/html.json | 22 +- .../docs/quickstart/execute-results/html.json | 30 +- .../docs/sampling/execute-results/html.json | 30 +- .../execute-results/html.json | 22 +- .../transformers/execute-results/html.json | 22 +- _freeze/site_libs/clipboard/clipboard.min.js | 12 +- _quarto.yml | 237 +- docs/.gitignore | 2 +- docs/Pyspatialml_training.svg | 8 +- docs/{quickstart.qmd => guide.qmd} | 338 +- docs/installation.qmd | 48 +- docs/landcover.qmd | 420 +- ...multitarget-regression-soil-properties.qmd | 568 +- docs/plotting.qmd | 138 +- docs/sampling.qmd | 84 +- docs/spatial-features.qmd | 302 +- docs/transformers.qmd | 134 +- docs/usage.qmd | 64 +- index.qmd | 110 +- poetry.lock | 3756 ------------ pyproject.toml | 84 +- pyspatialml/__init__.py | 4 +- pyspatialml/_plotting.py | 776 +-- pyspatialml/_prediction.py | 500 +- pyspatialml/_rasterstats.py | 274 +- pyspatialml/_utils.py | 88 +- pyspatialml/datasets/extracted_pixels.txt | 4872 +++++++-------- pyspatialml/datasets/meuse.py | 58 +- pyspatialml/datasets/nc.py | 28 +- pyspatialml/locindexer.py | 478 +- pyspatialml/preprocessing.py | 586 +- pyspatialml/raster.py | 5382 ++++++++--------- pyspatialml/rasterlayer.py | 880 +-- pyspatialml/transformers.py | 858 +-- pyspatialml/vector.py | 122 +- reference/Raster.qmd | 1224 ++-- reference/RasterLayer.qmd | 408 +- reference/index.qmd | 50 +- reference/preprocessing.qmd | 236 +- reference/vector.qmd | 100 +- tests/test_alter.py | 52 +- tests/test_append.py | 156 +- tests/test_apply.py | 130 +- tests/test_band_math.py | 66 +- tests/test_band_names.py | 106 +- tests/test_crop.py | 78 +- tests/test_drop.py | 118 +- tests/test_extract.py | 260 +- tests/test_indexing.py | 200 +- tests/test_initiation.py | 216 +- tests/test_intersect.py | 126 +- tests/test_mask.py | 158 +- tests/test_plotting.py | 82 +- tests/test_prediction.py | 430 +- tests/test_rename.py | 212 +- tests/test_sample.py | 82 +- tests/test_stats.py | 66 +- tests/test_tocrs.py | 124 +- tests/test_transformers.py | 30 +- tests/test_write.py | 56 +- 74 files changed, 12465 insertions(+), 16219 deletions(-) create mode 100644 _freeze/docs/guide/execute-results/html.json create mode 100644 _freeze/docs/guide/figure-html/cell-5-output-1.png create mode 100644 _freeze/docs/guide/figure-html/cell-8-output-1.png rename docs/{quickstart.qmd => guide.qmd} (96%) delete mode 100644 poetry.lock diff --git a/.github/workflows/publish-quarto.yml b/.github/workflows/publish-quarto.yml index ea3c14e..11f40fe 100644 --- a/.github/workflows/publish-quarto.yml +++ b/.github/workflows/publish-quarto.yml @@ -1,46 +1,39 @@ -name: Quarto Publish - -on: [push] - -jobs: - build-deploy: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Install system dependencies - run : | - sudo apt-get update - sudo apt-get upgrade - sudo apt-get install libudunits2-dev libgdal-dev libcurl4-openssl-dev - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Install the project - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: | - poetry install --no-interaction --no-root - - - name: Set up Quarto - uses: quarto-dev/quarto-actions/setup@v2 - - - name: Render and Publish - uses: quarto-dev/quarto-actions/publish@v2 - with: - target: gh-pages - env: +name: Quarto Publish + +on: [push] + +jobs: + build-deploy: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install system dependencies + run : | + sudo apt-get update + sudo apt-get upgrade + sudo apt-get install libudunits2-dev libgdal-dev libcurl4-openssl-dev + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install -r <(python -c 'import toml; print("\n".join(toml.load("pyproject.toml")["project"]["dependencies"]))') + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + + - name: Render and Publish + uses: quarto-dev/quarto-actions/publish@v2 + with: + target: gh-pages + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 22f61d5..9bef6b1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,59 +1,42 @@ -name: Pytest - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.9, '3.10', 3.11, 3.12] - - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install system dependencies - run: | - sudo apt-get update -y - sudo apt-get install gdal-bin libproj-dev libgdal-dev proj-bin - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Install package dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction - - # - name: Lint with flake8 - # run: | - # source .venv/bin/activate - # # stop the build if there are Python syntax errors or undefined names - # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - - name: Test with pytest - run: | - poetry run pytest --cov-report=xml --cov=. - - - name: "Upload Report to Codecov" - uses: codecov/codecov-action@v4.2.0 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - file: ./coverage.xml +name: Pytest + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9, '3.10', 3.11, 3.12] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install system dependencies + run: | + sudo apt-get update -y + sudo apt-get install gdal-bin libproj-dev libgdal-dev proj-bin + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install -r <(python -c 'import toml; print("\n".join(toml.load("pyproject.toml")["project"]["dependencies"]))') + + - name: Test with pytest + run: | + poetry run pytest --cov-report=xml --cov=. + + - name: "Upload Report to Codecov" + uses: codecov/codecov-action@v4.2.0 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + file: ./coverage.xml fail_ci_if_error: true \ No newline at end of file diff --git a/.gitignore b/.gitignore index e44e70e..0fb4366 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,16 @@ -.DS_Store -.eggs/ -.idea/ -.vscode/ -.pytest_cache/ -*__pycache__/ -build/ -*egg* -*whl -*.tar.gz -**/*.ipynb_checkpoints/ - -/.quarto/ -_site/ -site/ +.DS_Store +.eggs/ +.idea/ +.vscode/ +.pytest_cache/ +*__pycache__/ +build/ +*egg* +*whl +*.tar.gz +**/*.ipynb_checkpoints/ +.conda/ + +/.quarto/ +_site/ +site/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a92ee2b..6cab15f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files - - id: double-quote-string-fixer - -- repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.4.2 - hooks: - - id: black - name: black (python) - language_version: python3.11 +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: double-quote-string-fixer + +- repo: https://github.com/psf/black-pre-commit-mirror + rev: 24.4.2 + hooks: + - id: black + name: black (python) + language_version: python3.11 diff --git a/.python-version b/.python-version index 2419ad5..a9d3e48 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.11.9 +3.11.9 diff --git a/LICENSE b/LICENSE index 9cecc1d..c65825e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,674 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index ef18404..284baaf 100644 --- a/README.md +++ b/README.md @@ -1,433 +1,433 @@ -[![Codecov test coverage](https://codecov.io/gh/stevenpawley/pyspatialml/branch/master/graph/badge.svg)](https://codecov.io/gh/stevenpawley/pyspatialml?branch=master) -![Pytest](https://github.com/stevenpawley/pyspatialml/actions/workflows/tests.yml/badge.svg) - -# Pyspatialml -Machine learning classification and regression modelling for spatial raster data. - -## Description -`Pyspatialml` is a Python module for applying scikit-learn machine learning models to 'stacks' of raster datasets. -Pyspatialml includes functions and classes for working with multiple raster datasets and performing a typical machine -learning workflow consisting of extracting training data and applying the predict or predict_proba methods of -scikit-learn estimators to a stack of raster datasets. Pyspatialml is built upon the `rasterio` Python module for -all of the heavy lifting, and is also designed for working with vector data using the `geopandas` module. - -For more information read the documents page at: https://stevenpawley.github.io/Pyspatialml/ - -## Rationale -A typical supervised machine-learning workflow involving raster datasets consists of several steps: - -1. Using vector features or labelled pixels to extract training data from a stack of raster-based predictors (e.g. -spectral bands, terrain derivatives, or climate grids). The training data represent locations when some -property/state/concentration is already established, and might comprise point locations of arsenic concentrations, or -labelled pixels with integer-encoded values that correspond to known landcover types. - -2. Developing a machine learning classification or regression model on the training data. Pyspatialml is designed to use -scikit-learn compatible api's for this purpose. - -3. Applying the fitted machine learning model to make predictions on all of the pixels in the stack of raster data. - -Pyspatialml is designed to make it easy to develop spatial prediction models on stacks of 2D raster datasets that are -held on disk. Unlike using python's `numpy` module directly where raster datasets need to be held in memory, -the majority of functions within pyspatialml work with raster datasets that are stored on disk and allow processing -operations to be performed on datasets that are too large to be loaded into memory. - -## Design - -### Raster and RasterLayer objects - -The main class that facilitates working with multiple raster datasets is the `Raster` class, which is inspired by -the famous ```raster``` package in the R statistical programming language. The `Raster` object takes a list of file -paths to GDAL-supported raster datasets and 'stacks' them into a single Raster object. The underlying file-based raster -datasets are not physically-stacked, but rather the Raster object internally represents each band within the datasets as -a `RasterLayer`. This means that metadata regarding what each raster dataset represents (e.g. the dataset's name) -can be retained, and additional raster datasets can be added or removed from the stack without physical on disk changes. - -Note these raster datasets need to be spatially aligned in terms of their extent, resolution and coordinate reference -system. - -### Usage - -There are four methods of creating a new Raster object: - -1. `Raster([raster1.tif, raster2.tif, raster3.tif])` creates a Raster object from existing file-based -GDAL-supported datasets. - -2. `Raster(new_numpy_array, crs=crs, transform=transform)` creates a Raster object from a 3D numpy array (band, -row, column). The `crs` and `transform` arguments are optional but are required to provide coordinate reference -system information to the Raster object. The crs argument has to be represented by `rasterio.crs.CRS` object, and -the transform parameter requires a `affine.Affine` object. - -3. `Raster([RasterLayer1, RasterLayer2, RasterLayer3])` creates a Raster object from a single or list of -RasterLayer objects. RasterLayers are a thin wrapper around rasterio.Band objects with additional methods. This is -mostly used internally. A RasterLayer itself is initiated directly from a rasterio.Band object. - -4. `Raster([src0, src1, src2])` where the list elements are `rasterio.io.datasetreader` objects, i.e. raster -datasets that have been opened using the `rasterio.open` method. - -Generally, pyspatialml intends users to work with the Raster object. However, access to individual RasterLayer -objects, or the underlying rasterio.band datasets can be useful if pyspatialml is being used in conjunction with other -functions and methods in the Rasterio package. - -## Installation - -The package is now available on PyPI, but can also be installed from GitHub directly via: - -``` -pip install git+https://github.com/stevenpawley/Pyspatialml -``` - -## Quickstart - -This is an example using the imagery data that is bundled with the package. This data is derived from the GRASS GIS -North Carolina dataset and comprises Landsat 7 VNIR and SWIR bands along with some land cover training data that were -derived from a land cover classification from an earlier date. - -First, import the extract and predict functions: - -``` -from pyspatialml import Raster -from copy import deepcopy -import os -import tempfile -import geopandas -import rasterio.plot -import matplotlib.pyplot as plt -``` - -### Stacking - -We are going to use a set of Landsat 7 bands contained within the nc_dataset: - -``` -import pyspatialml.datasets.nc as nc -predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] -``` - -These raster datasets are aligned in terms of their extent and coordinate reference systems. We can 'stack' these into a -Raster class so that we can perform machine learning related operations on the set of rasters: - -``` -stack = Raster(predictors) -``` - -Upon 'stacking', syntactically-correct names for each RasterLayer are automatically generated from the file_paths. - -### Indexing - -Indexing of Raster objects is provided by several methods: - -- Raster[keys] : subsets a Raster using key-based indexing based on the names of the RasterLayers. If a single key is -supplied then a RasterLayer is returned, otherwise a Raster object is returned contained the subsetted layers. -- Raster.iloc[int, list, tuple, slice] : subsets a Raster using integer-based indexing or slicing. If a single key is -supplied then a RasterLayer is returned, otherwise a Raster object is returned contained the subsetted layers. -- Raster.name : attribute names can be used directly, and always returns a single RasterLayer object. - -RasterLayer indexing which returns a RasterLayer: - -``` -# index by integer position -rasterlayer = stack.iloc[0] -rasterstack = stack.iloc[0:3] - -# index by name -rasterlayer = stack['lsat7_2000_10'] -rasterstack = stack[('lsat7_2000_10', 'lsat7_2000_20')] - -# index by atttribute -rasterlayer = stack.lsat7_2000_10 -``` - -Iterate through RasterLayers: - -``` -for name, layer in stack: - print(layer) -``` - -Subset a Raster object: - -``` -subset_raster = stack[['lsat7_2000_10', 'lsat7_2000_70']] -subset_raster.names -``` - -Replace a RasterLayer with another: - -``` -stack.iloc[0] = Raster(nc.band7).iloc[0] -``` - -Append layers from another Raster to the stack. Note that this occurs in-place. Duplicate names are automatically given -a suffix: - -``` -stack.append(Raster(nc.band7)) -stack.names -``` - -Rename RasterLayers using a dict of old_name : new_name pairs: - -``` -stack.names -stack.rename({'lsat7_2000_30': 'new_name'}, in_place=True) -stack.names -stack.new_name -stack['new_name'] -stack.loc['new_name'] -``` - -We can also change all of the column names by replacing them: - -``` -stack.names = ["band1", "band2", "band3", "band4", "band5", "band7"] -``` - -Drop a RasterLayer: - -``` -stack.names -stack.drop(labels='band1', in_place=True) -stack.names -``` - -Save a Raster: - -``` -tmp_tif = tempfile.NamedTemporaryFile().name + '.tif' -newstack = stack.write(file_path=tmp_tif, nodata=-9999) -newstack.band2.read() -``` - -### Plotting - -Basic plotting has been added to as a method to RasterLayer and Raster options. More controls on plotting will be added -in the future. Currently you can set a matplotlib cmap for each RasterLayer using the RasterLayer.cmap attribute. - -Plot a single RasterLayer: - -``` -from matplotlib.colors import Normalize - -stack = Raster(predictors) -stack.lsat7_2000_10.cmap = 'plasma' -stack.lsat7_2000_10.norm = Normalize(20, 210) -stack.lsat7_2000_10.plot() -``` - -Plot all RasterLayers in a Raster object: - -``` -stack.plot() -``` - -### Integration with Pandas - -Data from a Raster object can be converted into a Pandas dataframe, with each pixel representing by a row, and columns -reflecting the x, y coordinates and the values of each RasterLayer in the Raster object: - -``` -df = stack.to_pandas(max_pixels=50000, resampling='nearest') -df.head() -``` - -The original raster is up-sampled based on max_pixels and the resampling method, which uses all of resampling methods -available in the underlying rasterio library for decimated reads. The Raster.to_pandas method can be useful for plotting -datasets, or combining with a library such as plotnine to create ggplot2-style plots of stacks of RasterLayers: - -``` -from plotnine import * -(ggplot(df.melt(id_vars=['x', 'y']), aes(x='x', y='y', fill='value')) + -geom_tile() + facet_wrap('variable')) -``` - -## A Machine Learning Workflow - -### Extract Training Data - -Load some training data in the form of polygons, points and labelled pixels in geopandas GeoDataFrame objects. We will -also generate some line geometries by converting the polygon boundaries into linestrings. All of these geometry types -can be used to spatially query pixel values in a Raster object, however each GeoDataFrame must contain only one type of -geometry (i.e. either shapely points, polygons or linestrings). - -``` -training_py = geopandas.read_file(nc.polygons) -training_pt = geopandas.read_file(nc.points) -training_px = rasterio.open(nc.labelled_pixels) -training_lines = deepcopy(training_py) -training_lines['geometry'] = training_lines.geometry.boundary -``` - -Show training data points and a single raster band using numpy and matplotlib: - -``` -stack = Raster(predictors) -plt.imshow(stack.lsat7_2000_70.read(masked=True), - extent=rasterio.plot.plotting_extent(stack.lsat7_2000_70)) -plt.scatter(x=training_pt.bounds.iloc[:, 0], - y=training_pt.bounds.iloc[:, 1], - s=2, color='black') -plt.show() -``` - -Pixel values in the Raster object can be spatially queried using the `extract_vector` and `extract_raster` -methods. In addition, the `extract_xy` method can be used to query pixel values using a 2d array of x and y -coordinates. - -The `extract_vector` method accepts a Geopandas GeoDataFrame as the `gdf` argument. For -GeoDataFrames containing shapely point geometries, the closest pixel to each point is sampled. For shapely polygon -geometries, all pixels whose centres are inside the polygon are sampled. For shapely linestring geometries, every pixel -touched by the line is sampled. For all geometry types, pixel values are queries for each geometry separately. This -means that overlapping polygons or points that fall within the same pixel with cause the same pixel to be sampled -multiple times. - -By default, the extract functions return a Geopandas GeoDataFrame of point geometries and the DataFrame containing the -extracted pixels, with the column names set by the names of the raster datasets in the Raster object. The user can also -use the `return_array=True` argument, which instead of returning a DataFrame will return three masked numpy arrays -(id, X, coordinates) containing geodataframe indices, the extracted pixel values, and the spatial coordinates of the sampled -pixels. These arrays are masked arrays with nodata values in the RasterStack datasets being masked. - -The `extract_raster` method can also be used to spatially query pixel values from a Raster object using another -raster containing labelled pixels. This raster has to be spatially aligned with the Raster object. This method also returns -the values of the labelled pixels along with the queried pixel values. - -``` -# Create a training dataset by extracting the raster values at the training point locations: -df_points = stack.extract_vector(training_pt) -df_polygons = stack.extract_vector(training_py) -df_lines = stack.extract_vector(training_lines) -df_raster = stack.extract_raster(training_px) - -df_points.head() - -# join the extracted pixel data back with the training data -df_points = df_points.droplevel(0).merge( - training_pt.loc[:, ("id")], - left_index=True, - right_index=True -) -df_points = df_points.dropna() -``` - -### Model Training - -Next we can train a logistic regression classifier: - -``` -# Next we can train a logistic regression classifier: -from sklearn.linear_model import LogisticRegressionCV -from sklearn.preprocessing import StandardScaler -from sklearn.pipeline import Pipeline -from sklearn.model_selection import cross_validate - -# define the classifier with standardization of the input features in a pipeline -lr = Pipeline( - [('scaling', StandardScaler()), - ('classifier', LogisticRegressionCV(n_jobs=-1))]) - -# fit the classifier -X = df_points.drop(columns=["geometry", "id"]) -y = df_points.id -lr.fit(X, y) -```` - -After defining a classifier, a typical step consists of performing a cross-validation to evaluate the performance of the -model. Scikit-learn provides the cross_validate function for this purpose. In comparison to non-spatial data, spatial -data can be spatially correlated, which potentially can mean that geographically proximal samples may not represent -independent samples if they are within the autocorrelation range of some of the predictors. This will lead to overly -optimistic performance measures if samples in the training dataset / cross-validation partition are strongly spatially -correlated with samples in the test dataset / cross-validation partition. - -In this case, performing cross-validation using groups is useful, because these groups can represent spatial clusters of -training samples, and samples from the same group will never occur in both the training and test partitions of a -cross-validation. An example of creating random spatial clusters from point coordinates is provided here: - -``` -# spatial cross-validation -from sklearn.cluster import KMeans - -# create 10 spatial clusters based on clustering of the training data point x,y coordinates -clusters = KMeans(n_clusters=34, n_jobs=-1) -clusters.fit(df_points.geometry.bounds.iloc[:, 0:2]) - -# cross validate -scores = cross_validate( - lr, X, y, groups=clusters.labels_, - scoring='accuracy', - cv=3, n_jobs=1) -scores['test_score'].mean() -``` - -### Raster Prediction - -Prediction on the Raster object is performed using the `predict` and `predict_proba` methods. The `estimator` is the only required -argument. If the `file_path` argument is not specified then the result is automatically written to a temporary file. -The predict method returns an rasterio.io.DatasetReader object which is open. For probability prediction, -`indexes` can also be supplied if you only want to output the probabilities for a particular class, or list of -classes, by supplying the indices of those classes: - -``` -# prediction -result = stack.predict(estimator=lr, dtype='int16', nodata=0) -result_probs = stack.predict_proba(estimator=lr) - -# plot classification result -result.plot() -plt.show() - -# plot class probabilities -result_probs.plot() -plt.show() -``` - -## Sampling Tools - -For many spatial models, it is common to take a random sample of the predictors to represent a single class (i.e. an -environmental background or pseudo-absences in a binary classification model). The sample function is supplied in the -sampling module for this purpose: -``` -# extract training data using a random sample -df_rand = stack.sample(size=100, random_state=1) -df_rand.plot() -``` - -The sample function also enables stratified random sampling based on passing a categorical raster dataset to the strata -argument. The categorical raster should spatially overlap with the dataset to be sampled, but it does not need to be of -the same grid resolution. This raster should be passed as another `Raster` dataset containing a single categorical layer: - -``` -strata = Raster(nc.strata) -df_strata = stack.sample(size=5, strata=strata, random_state=1) -df_strata = df_strata.dropna() - -fig, ax = plt.subplots() -ax.imshow(strata.read(1, masked=True), extent=rasterio.plot.plotting_extent(strata), cmap='tab10') -df_strata.plot(ax=ax, markersize=20, color='white') -plt.show() -``` - -## Vector Data Tools - -In some cases, we don't need all of the training data, but rather would spatially thin a point dataset. The -filter_points function performs point-thinning based on a minimum distance buffer on a geopandas dataframe containing -point geometries: - -``` -from pyspatialml.vector import filter_points - -thinned_points = filter_points(training_pt, min_dist=500, remove='first') -thinned_points.shape -``` - -We can also generate random points within polygons using the get_random_point_in_polygon function. This requires a -shapely POLYGON geometry as an input, and returns a shapely POINT object: - -``` -from pyspatialml.vector import get_random_point_in_polygon - -# generate 5 random points in a single polygon -random_points = [get_random_point_in_polygon(training_py.geometry[0]) for i in range(5)] - -# convert to a GeoDataFrame -random_points = geopandas.GeoDataFrame( - geometry=geopandas.GeoSeries(random_points)) -``` +[![Codecov test coverage](https://codecov.io/gh/stevenpawley/pyspatialml/branch/master/graph/badge.svg)](https://codecov.io/gh/stevenpawley/pyspatialml?branch=master) +![Pytest](https://github.com/stevenpawley/pyspatialml/actions/workflows/tests.yml/badge.svg) + +# Pyspatialml +Machine learning classification and regression modelling for spatial raster data. + +## Description +`Pyspatialml` is a Python module for applying scikit-learn machine learning models to 'stacks' of raster datasets. +Pyspatialml includes functions and classes for working with multiple raster datasets and performing a typical machine +learning workflow consisting of extracting training data and applying the predict or predict_proba methods of +scikit-learn estimators to a stack of raster datasets. Pyspatialml is built upon the `rasterio` Python module for +all of the heavy lifting, and is also designed for working with vector data using the `geopandas` module. + +For more information read the documents page at: https://stevenpawley.github.io/Pyspatialml/ + +## Rationale +A typical supervised machine-learning workflow involving raster datasets consists of several steps: + +1. Using vector features or labelled pixels to extract training data from a stack of raster-based predictors (e.g. +spectral bands, terrain derivatives, or climate grids). The training data represent locations when some +property/state/concentration is already established, and might comprise point locations of arsenic concentrations, or +labelled pixels with integer-encoded values that correspond to known landcover types. + +2. Developing a machine learning classification or regression model on the training data. Pyspatialml is designed to use +scikit-learn compatible api's for this purpose. + +3. Applying the fitted machine learning model to make predictions on all of the pixels in the stack of raster data. + +Pyspatialml is designed to make it easy to develop spatial prediction models on stacks of 2D raster datasets that are +held on disk. Unlike using python's `numpy` module directly where raster datasets need to be held in memory, +the majority of functions within pyspatialml work with raster datasets that are stored on disk and allow processing +operations to be performed on datasets that are too large to be loaded into memory. + +## Design + +### Raster and RasterLayer objects + +The main class that facilitates working with multiple raster datasets is the `Raster` class, which is inspired by +the famous ```raster``` package in the R statistical programming language. The `Raster` object takes a list of file +paths to GDAL-supported raster datasets and 'stacks' them into a single Raster object. The underlying file-based raster +datasets are not physically-stacked, but rather the Raster object internally represents each band within the datasets as +a `RasterLayer`. This means that metadata regarding what each raster dataset represents (e.g. the dataset's name) +can be retained, and additional raster datasets can be added or removed from the stack without physical on disk changes. + +Note these raster datasets need to be spatially aligned in terms of their extent, resolution and coordinate reference +system. + +### Usage + +There are four methods of creating a new Raster object: + +1. `Raster([raster1.tif, raster2.tif, raster3.tif])` creates a Raster object from existing file-based +GDAL-supported datasets. + +2. `Raster(new_numpy_array, crs=crs, transform=transform)` creates a Raster object from a 3D numpy array (band, +row, column). The `crs` and `transform` arguments are optional but are required to provide coordinate reference +system information to the Raster object. The crs argument has to be represented by `rasterio.crs.CRS` object, and +the transform parameter requires a `affine.Affine` object. + +3. `Raster([RasterLayer1, RasterLayer2, RasterLayer3])` creates a Raster object from a single or list of +RasterLayer objects. RasterLayers are a thin wrapper around rasterio.Band objects with additional methods. This is +mostly used internally. A RasterLayer itself is initiated directly from a rasterio.Band object. + +4. `Raster([src0, src1, src2])` where the list elements are `rasterio.io.datasetreader` objects, i.e. raster +datasets that have been opened using the `rasterio.open` method. + +Generally, pyspatialml intends users to work with the Raster object. However, access to individual RasterLayer +objects, or the underlying rasterio.band datasets can be useful if pyspatialml is being used in conjunction with other +functions and methods in the Rasterio package. + +## Installation + +The package is now available on PyPI, but can also be installed from GitHub directly via: + +``` +pip install git+https://github.com/stevenpawley/Pyspatialml +``` + +## Quickstart + +This is an example using the imagery data that is bundled with the package. This data is derived from the GRASS GIS +North Carolina dataset and comprises Landsat 7 VNIR and SWIR bands along with some land cover training data that were +derived from a land cover classification from an earlier date. + +First, import the extract and predict functions: + +``` +from pyspatialml import Raster +from copy import deepcopy +import os +import tempfile +import geopandas +import rasterio.plot +import matplotlib.pyplot as plt +``` + +### Stacking + +We are going to use a set of Landsat 7 bands contained within the nc_dataset: + +``` +import pyspatialml.datasets.nc as nc +predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] +``` + +These raster datasets are aligned in terms of their extent and coordinate reference systems. We can 'stack' these into a +Raster class so that we can perform machine learning related operations on the set of rasters: + +``` +stack = Raster(predictors) +``` + +Upon 'stacking', syntactically-correct names for each RasterLayer are automatically generated from the file_paths. + +### Indexing + +Indexing of Raster objects is provided by several methods: + +- Raster[keys] : subsets a Raster using key-based indexing based on the names of the RasterLayers. If a single key is +supplied then a RasterLayer is returned, otherwise a Raster object is returned contained the subsetted layers. +- Raster.iloc[int, list, tuple, slice] : subsets a Raster using integer-based indexing or slicing. If a single key is +supplied then a RasterLayer is returned, otherwise a Raster object is returned contained the subsetted layers. +- Raster.name : attribute names can be used directly, and always returns a single RasterLayer object. + +RasterLayer indexing which returns a RasterLayer: + +``` +# index by integer position +rasterlayer = stack.iloc[0] +rasterstack = stack.iloc[0:3] + +# index by name +rasterlayer = stack['lsat7_2000_10'] +rasterstack = stack[('lsat7_2000_10', 'lsat7_2000_20')] + +# index by atttribute +rasterlayer = stack.lsat7_2000_10 +``` + +Iterate through RasterLayers: + +``` +for name, layer in stack: + print(layer) +``` + +Subset a Raster object: + +``` +subset_raster = stack[['lsat7_2000_10', 'lsat7_2000_70']] +subset_raster.names +``` + +Replace a RasterLayer with another: + +``` +stack.iloc[0] = Raster(nc.band7).iloc[0] +``` + +Append layers from another Raster to the stack. Note that this occurs in-place. Duplicate names are automatically given +a suffix: + +``` +stack.append(Raster(nc.band7)) +stack.names +``` + +Rename RasterLayers using a dict of old_name : new_name pairs: + +``` +stack.names +stack.rename({'lsat7_2000_30': 'new_name'}, in_place=True) +stack.names +stack.new_name +stack['new_name'] +stack.loc['new_name'] +``` + +We can also change all of the column names by replacing them: + +``` +stack.names = ["band1", "band2", "band3", "band4", "band5", "band7"] +``` + +Drop a RasterLayer: + +``` +stack.names +stack.drop(labels='band1', in_place=True) +stack.names +``` + +Save a Raster: + +``` +tmp_tif = tempfile.NamedTemporaryFile().name + '.tif' +newstack = stack.write(file_path=tmp_tif, nodata=-9999) +newstack.band2.read() +``` + +### Plotting + +Basic plotting has been added to as a method to RasterLayer and Raster options. More controls on plotting will be added +in the future. Currently you can set a matplotlib cmap for each RasterLayer using the RasterLayer.cmap attribute. + +Plot a single RasterLayer: + +``` +from matplotlib.colors import Normalize + +stack = Raster(predictors) +stack.lsat7_2000_10.cmap = 'plasma' +stack.lsat7_2000_10.norm = Normalize(20, 210) +stack.lsat7_2000_10.plot() +``` + +Plot all RasterLayers in a Raster object: + +``` +stack.plot() +``` + +### Integration with Pandas + +Data from a Raster object can be converted into a Pandas dataframe, with each pixel representing by a row, and columns +reflecting the x, y coordinates and the values of each RasterLayer in the Raster object: + +``` +df = stack.to_pandas(max_pixels=50000, resampling='nearest') +df.head() +``` + +The original raster is up-sampled based on max_pixels and the resampling method, which uses all of resampling methods +available in the underlying rasterio library for decimated reads. The Raster.to_pandas method can be useful for plotting +datasets, or combining with a library such as plotnine to create ggplot2-style plots of stacks of RasterLayers: + +``` +from plotnine import * +(ggplot(df.melt(id_vars=['x', 'y']), aes(x='x', y='y', fill='value')) + +geom_tile() + facet_wrap('variable')) +``` + +## A Machine Learning Workflow + +### Extract Training Data + +Load some training data in the form of polygons, points and labelled pixels in geopandas GeoDataFrame objects. We will +also generate some line geometries by converting the polygon boundaries into linestrings. All of these geometry types +can be used to spatially query pixel values in a Raster object, however each GeoDataFrame must contain only one type of +geometry (i.e. either shapely points, polygons or linestrings). + +``` +training_py = geopandas.read_file(nc.polygons) +training_pt = geopandas.read_file(nc.points) +training_px = rasterio.open(nc.labelled_pixels) +training_lines = deepcopy(training_py) +training_lines['geometry'] = training_lines.geometry.boundary +``` + +Show training data points and a single raster band using numpy and matplotlib: + +``` +stack = Raster(predictors) +plt.imshow(stack.lsat7_2000_70.read(masked=True), + extent=rasterio.plot.plotting_extent(stack.lsat7_2000_70)) +plt.scatter(x=training_pt.bounds.iloc[:, 0], + y=training_pt.bounds.iloc[:, 1], + s=2, color='black') +plt.show() +``` + +Pixel values in the Raster object can be spatially queried using the `extract_vector` and `extract_raster` +methods. In addition, the `extract_xy` method can be used to query pixel values using a 2d array of x and y +coordinates. + +The `extract_vector` method accepts a Geopandas GeoDataFrame as the `gdf` argument. For +GeoDataFrames containing shapely point geometries, the closest pixel to each point is sampled. For shapely polygon +geometries, all pixels whose centres are inside the polygon are sampled. For shapely linestring geometries, every pixel +touched by the line is sampled. For all geometry types, pixel values are queries for each geometry separately. This +means that overlapping polygons or points that fall within the same pixel with cause the same pixel to be sampled +multiple times. + +By default, the extract functions return a Geopandas GeoDataFrame of point geometries and the DataFrame containing the +extracted pixels, with the column names set by the names of the raster datasets in the Raster object. The user can also +use the `return_array=True` argument, which instead of returning a DataFrame will return three masked numpy arrays +(id, X, coordinates) containing geodataframe indices, the extracted pixel values, and the spatial coordinates of the sampled +pixels. These arrays are masked arrays with nodata values in the RasterStack datasets being masked. + +The `extract_raster` method can also be used to spatially query pixel values from a Raster object using another +raster containing labelled pixels. This raster has to be spatially aligned with the Raster object. This method also returns +the values of the labelled pixels along with the queried pixel values. + +``` +# Create a training dataset by extracting the raster values at the training point locations: +df_points = stack.extract_vector(training_pt) +df_polygons = stack.extract_vector(training_py) +df_lines = stack.extract_vector(training_lines) +df_raster = stack.extract_raster(training_px) + +df_points.head() + +# join the extracted pixel data back with the training data +df_points = df_points.droplevel(0).merge( + training_pt.loc[:, ("id")], + left_index=True, + right_index=True +) +df_points = df_points.dropna() +``` + +### Model Training + +Next we can train a logistic regression classifier: + +``` +# Next we can train a logistic regression classifier: +from sklearn.linear_model import LogisticRegressionCV +from sklearn.preprocessing import StandardScaler +from sklearn.pipeline import Pipeline +from sklearn.model_selection import cross_validate + +# define the classifier with standardization of the input features in a pipeline +lr = Pipeline( + [('scaling', StandardScaler()), + ('classifier', LogisticRegressionCV(n_jobs=-1))]) + +# fit the classifier +X = df_points.drop(columns=["geometry", "id"]) +y = df_points.id +lr.fit(X, y) +```` + +After defining a classifier, a typical step consists of performing a cross-validation to evaluate the performance of the +model. Scikit-learn provides the cross_validate function for this purpose. In comparison to non-spatial data, spatial +data can be spatially correlated, which potentially can mean that geographically proximal samples may not represent +independent samples if they are within the autocorrelation range of some of the predictors. This will lead to overly +optimistic performance measures if samples in the training dataset / cross-validation partition are strongly spatially +correlated with samples in the test dataset / cross-validation partition. + +In this case, performing cross-validation using groups is useful, because these groups can represent spatial clusters of +training samples, and samples from the same group will never occur in both the training and test partitions of a +cross-validation. An example of creating random spatial clusters from point coordinates is provided here: + +``` +# spatial cross-validation +from sklearn.cluster import KMeans + +# create 10 spatial clusters based on clustering of the training data point x,y coordinates +clusters = KMeans(n_clusters=34, n_jobs=-1) +clusters.fit(df_points.geometry.bounds.iloc[:, 0:2]) + +# cross validate +scores = cross_validate( + lr, X, y, groups=clusters.labels_, + scoring='accuracy', + cv=3, n_jobs=1) +scores['test_score'].mean() +``` + +### Raster Prediction + +Prediction on the Raster object is performed using the `predict` and `predict_proba` methods. The `estimator` is the only required +argument. If the `file_path` argument is not specified then the result is automatically written to a temporary file. +The predict method returns an rasterio.io.DatasetReader object which is open. For probability prediction, +`indexes` can also be supplied if you only want to output the probabilities for a particular class, or list of +classes, by supplying the indices of those classes: + +``` +# prediction +result = stack.predict(estimator=lr, dtype='int16', nodata=0) +result_probs = stack.predict_proba(estimator=lr) + +# plot classification result +result.plot() +plt.show() + +# plot class probabilities +result_probs.plot() +plt.show() +``` + +## Sampling Tools + +For many spatial models, it is common to take a random sample of the predictors to represent a single class (i.e. an +environmental background or pseudo-absences in a binary classification model). The sample function is supplied in the +sampling module for this purpose: +``` +# extract training data using a random sample +df_rand = stack.sample(size=100, random_state=1) +df_rand.plot() +``` + +The sample function also enables stratified random sampling based on passing a categorical raster dataset to the strata +argument. The categorical raster should spatially overlap with the dataset to be sampled, but it does not need to be of +the same grid resolution. This raster should be passed as another `Raster` dataset containing a single categorical layer: + +``` +strata = Raster(nc.strata) +df_strata = stack.sample(size=5, strata=strata, random_state=1) +df_strata = df_strata.dropna() + +fig, ax = plt.subplots() +ax.imshow(strata.read(1, masked=True), extent=rasterio.plot.plotting_extent(strata), cmap='tab10') +df_strata.plot(ax=ax, markersize=20, color='white') +plt.show() +``` + +## Vector Data Tools + +In some cases, we don't need all of the training data, but rather would spatially thin a point dataset. The +filter_points function performs point-thinning based on a minimum distance buffer on a geopandas dataframe containing +point geometries: + +``` +from pyspatialml.vector import filter_points + +thinned_points = filter_points(training_pt, min_dist=500, remove='first') +thinned_points.shape +``` + +We can also generate random points within polygons using the get_random_point_in_polygon function. This requires a +shapely POLYGON geometry as an input, and returns a shapely POINT object: + +``` +from pyspatialml.vector import get_random_point_in_polygon + +# generate 5 random points in a single polygon +random_points = [get_random_point_in_polygon(training_py.geometry[0]) for i in range(5)] + +# convert to a GeoDataFrame +random_points = geopandas.GeoDataFrame( + geometry=geopandas.GeoSeries(random_points)) +``` diff --git a/_freeze/docs/geoprocessing/execute-results/html.json b/_freeze/docs/geoprocessing/execute-results/html.json index 6691e06..d415e02 100644 --- a/_freeze/docs/geoprocessing/execute-results/html.json +++ b/_freeze/docs/geoprocessing/execute-results/html.json @@ -1,12 +1,12 @@ -{ - "hash": "5f253fe0d4b07a283614d077bb8a5e51", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Raster Geoprocessing\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nPyspatialml includes common geoprocessing methods that collectively operate on\nstacks of raster datasets, such as cropping, reprojecting, masking etc. Most\nof these methods are simple wrappers around underlying rasterio functions, but\napplied to stacks of raster datasets.\n\n## Handling of Temporary Files\n\nAll of the geoprocessing methods have a `file_path` parameter to specify a file\npath to save the results of th geoprocessing operation. However, pyspatialml is\ndesigned for quick an interactive analyses on raster datasets, and if a file\npath is not specified then the results are saved to a temporary file location\nand a new Raster object is returned with the geoprocessing results.\n\nFor datasets that will easily fit into memory, all geoprocessing methods also\nhave an `in_memory` parameter. If `in_memory=True` is set, then the results\nwill be created using Rasterio's in-memory files and stored in RAM. This has\nperformance advantages, at the expense of memory expenditure.\n\n## Cropping\n\nAll layers within a Raster can be cropped to a new extent using the\n`Raster.crop` method.\n\n::: {#70f3733f .cell execution_count=1}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport matplotlib.pyplot as plt\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\ntraining_py = gpd.read_file(nc.polygons)\n\nstack = Raster(predictors)\n\nstack.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](geoprocessing_files/figure-html/cell-2-output-1.png){width=604 height=372}\n:::\n:::\n\n\n::: {#d43b4f2d .cell execution_count=2}\n``` {.python .cell-code}\n# crop to new extent (xmin, ymin, xmax, ymax)\ncrop_bounds = training_py.loc[0, \"geometry\"].bounds\nstack_cropped = stack.crop(crop_bounds)\n\nstack_cropped.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](geoprocessing_files/figure-html/cell-3-output-1.png){width=604 height=370}\n:::\n:::\n\n\n## Masking\n\nIn comparison to cropping, masking can be used to set pixels that occur outside\nof masking geometries to NaN, and optionally can also crop a Raster.\n\n::: {#33fabaa0 .cell execution_count=3}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport pyspatialml.datasets.nc as nc\nfrom pyspatialml import Raster\n\ntraining_py = gpd.read_file(nc.polygons)\nmask_py = training_py.iloc[0:1, :]\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\n# mask a Raster\nmasked_object = stack.mask(mask_py)\n```\n:::\n\n\n## Intersecting Layers\n\nThe `Raster.intersect` method computes the geometric intersection of the\nRasterLayers with the Raster object. This will cause nodata values in any of\nthe rasters to be propagated through all of the output rasters.\n\n::: {#d7a7ebe7 .cell execution_count=4}\n``` {.python .cell-code}\nimport pyspatialml.datasets.nc as nc\nfrom pyspatialml import Raster\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\nresult = stack.intersect()\n```\n:::\n\n\nThe intersect method is memory-safe, i.e. the intersection occurs during\nwindowed reading and writing of the Raster. The size and dimensions of the\nwindows can be changed using the `Raster.block_shapes` property.\n\n## Reprojecting\n\nReprojecting a raster using the `Raster.to_crs` method.\n\n::: {#8f71eb11 .cell execution_count=5}\n``` {.python .cell-code}\nstack_prj = stack.to_crs(crs={\"init\": \"EPSG:4326\"})\n```\n:::\n\n\nOther parameters that can be passed and their defaults are\nresampling=\"nearest\", file_path=None, driver=\"GTiff\", nodata=None, n_jobs=1,\nwarp_mem_lim=0, progress=False, and other kwargs that are passed to the raster\nformat drivers.\n\n## Resampling\n\nThe `Raster.aggregate` method is used to resample a raster to a different\nresolution using the decimated reading approach in the rasterio library.\n\n::: {#1452d771 .cell execution_count=6}\n``` {.python .cell-code}\nstack.aggregate(out_shape=(50, 50), resampling=\"nearest\", driver=\"GTiff\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 6 Layers\n attribute values\n0 names [lsat7_2000_10, lsat7_2000_20, lsat7_2000_30, ...\n1 files [/var/folders/_m/kbp8r1612yj1xl6ndb2y8vpm0000g...\n2 rows 50\n3 cols 50\n4 res (278.73, 252.51)\n5 nodatavals [-3.4028234663852886e+38, -3.4028234663852886e...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n\n```\n:::\n:::\n\n\n## Computation\n\nApply user-supplied function to a Raster object.\n\n::: {#ac19dac5 .cell execution_count=7}\n``` {.python .cell-code}\ndef myfun(x):\n return x + 1\n\nstack.apply(myfun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 6 Layers\n attribute values\n0 names [tmp0n2yd7no_1, tmp0n2yd7no_2, tmp0n2yd7no_3, ...\n1 files [/var/folders/_m/kbp8r1612yj1xl6ndb2y8vpm0000g...\n2 rows 443\n3 cols 489\n4 res (28.5, 28.5)\n5 nodatavals [-3.4028234663852886e+38, -3.4028234663852886e...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\n\n```\n:::\n:::\n\n\nWhere `function` is a user-defined python that takes an numpy array as a\nsingle argument, and can return either a 2d array that represents a single\nraster dataset, such as NDVI, or can operate on a number of layers and can\nreturn a raster with multiple layers in a 3d array in (layer, row, col)\norder.\n\nThe apply function is memory-safe, i.e. it applies the function to windows\nof the raster data that are read sequentially or in parallel\n(with n_jobs != 1). The size and dimensions of the windows can be changed\nusing the `Raster.block_shapes` property.\n\n## Raster Algebra\n\nRasterLayer objects also support basic raster math operations using python's\nmagic methods, which supports all of the usual math operators. Calculations\non RasterLayers occur in memory using Rasterio's in-memory files, thus they\nare not memory safe. For applying computations and algebra to large raster\ndatasets in windows, use `Raster.apply()`.\n\n::: {#a90b8434 .cell execution_count=8}\n``` {.python .cell-code}\na = stack.iloc[0] + stack.iloc[1]\nb = stack.iloc[0] - stack.iloc[1]\n\nndvi = (stack.iloc[3] - stack.iloc[2]) / (stack.iloc[3] + stack.iloc[2])\n```\n:::\n\n\nArithmetic operations on RasterLayer's will return another RasterLayer. The\nresult can be coerced into a Raster object using:\n\n::: {#0ce834ce .cell execution_count=9}\n``` {.python .cell-code}\nndvi = Raster((stack.iloc[3] - stack.iloc[2]) / (stack.iloc[3] + stack.iloc[2]))\n```\n:::\n\n\nArithmetic operations are only supported on RasterLayer objects and\nnot in a parent Raster object directly.\n\n", - "supporting": [ - "geoprocessing_files" - ], - "filters": [], - "includes": {} - } +{ + "hash": "5f253fe0d4b07a283614d077bb8a5e51", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Raster Geoprocessing\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nPyspatialml includes common geoprocessing methods that collectively operate on\nstacks of raster datasets, such as cropping, reprojecting, masking etc. Most\nof these methods are simple wrappers around underlying rasterio functions, but\napplied to stacks of raster datasets.\n\n## Handling of Temporary Files\n\nAll of the geoprocessing methods have a `file_path` parameter to specify a file\npath to save the results of th geoprocessing operation. However, pyspatialml is\ndesigned for quick an interactive analyses on raster datasets, and if a file\npath is not specified then the results are saved to a temporary file location\nand a new Raster object is returned with the geoprocessing results.\n\nFor datasets that will easily fit into memory, all geoprocessing methods also\nhave an `in_memory` parameter. If `in_memory=True` is set, then the results\nwill be created using Rasterio's in-memory files and stored in RAM. This has\nperformance advantages, at the expense of memory expenditure.\n\n## Cropping\n\nAll layers within a Raster can be cropped to a new extent using the\n`Raster.crop` method.\n\n::: {#70f3733f .cell execution_count=1}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport matplotlib.pyplot as plt\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\ntraining_py = gpd.read_file(nc.polygons)\n\nstack = Raster(predictors)\n\nstack.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](geoprocessing_files/figure-html/cell-2-output-1.png){width=604 height=372}\n:::\n:::\n\n\n::: {#d43b4f2d .cell execution_count=2}\n``` {.python .cell-code}\n# crop to new extent (xmin, ymin, xmax, ymax)\ncrop_bounds = training_py.loc[0, \"geometry\"].bounds\nstack_cropped = stack.crop(crop_bounds)\n\nstack_cropped.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](geoprocessing_files/figure-html/cell-3-output-1.png){width=604 height=370}\n:::\n:::\n\n\n## Masking\n\nIn comparison to cropping, masking can be used to set pixels that occur outside\nof masking geometries to NaN, and optionally can also crop a Raster.\n\n::: {#33fabaa0 .cell execution_count=3}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport pyspatialml.datasets.nc as nc\nfrom pyspatialml import Raster\n\ntraining_py = gpd.read_file(nc.polygons)\nmask_py = training_py.iloc[0:1, :]\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\n# mask a Raster\nmasked_object = stack.mask(mask_py)\n```\n:::\n\n\n## Intersecting Layers\n\nThe `Raster.intersect` method computes the geometric intersection of the\nRasterLayers with the Raster object. This will cause nodata values in any of\nthe rasters to be propagated through all of the output rasters.\n\n::: {#d7a7ebe7 .cell execution_count=4}\n``` {.python .cell-code}\nimport pyspatialml.datasets.nc as nc\nfrom pyspatialml import Raster\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\nresult = stack.intersect()\n```\n:::\n\n\nThe intersect method is memory-safe, i.e. the intersection occurs during\nwindowed reading and writing of the Raster. The size and dimensions of the\nwindows can be changed using the `Raster.block_shapes` property.\n\n## Reprojecting\n\nReprojecting a raster using the `Raster.to_crs` method.\n\n::: {#8f71eb11 .cell execution_count=5}\n``` {.python .cell-code}\nstack_prj = stack.to_crs(crs={\"init\": \"EPSG:4326\"})\n```\n:::\n\n\nOther parameters that can be passed and their defaults are\nresampling=\"nearest\", file_path=None, driver=\"GTiff\", nodata=None, n_jobs=1,\nwarp_mem_lim=0, progress=False, and other kwargs that are passed to the raster\nformat drivers.\n\n## Resampling\n\nThe `Raster.aggregate` method is used to resample a raster to a different\nresolution using the decimated reading approach in the rasterio library.\n\n::: {#1452d771 .cell execution_count=6}\n``` {.python .cell-code}\nstack.aggregate(out_shape=(50, 50), resampling=\"nearest\", driver=\"GTiff\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 6 Layers\n attribute values\n0 names [lsat7_2000_10, lsat7_2000_20, lsat7_2000_30, ...\n1 files [/var/folders/_m/kbp8r1612yj1xl6ndb2y8vpm0000g...\n2 rows 50\n3 cols 50\n4 res (278.73, 252.51)\n5 nodatavals [-3.4028234663852886e+38, -3.4028234663852886e...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n\n```\n:::\n:::\n\n\n## Computation\n\nApply user-supplied function to a Raster object.\n\n::: {#ac19dac5 .cell execution_count=7}\n``` {.python .cell-code}\ndef myfun(x):\n return x + 1\n\nstack.apply(myfun)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 6 Layers\n attribute values\n0 names [tmp0n2yd7no_1, tmp0n2yd7no_2, tmp0n2yd7no_3, ...\n1 files [/var/folders/_m/kbp8r1612yj1xl6ndb2y8vpm0000g...\n2 rows 443\n3 cols 489\n4 res (28.5, 28.5)\n5 nodatavals [-3.4028234663852886e+38, -3.4028234663852886e...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\n\n```\n:::\n:::\n\n\nWhere `function` is a user-defined python that takes an numpy array as a\nsingle argument, and can return either a 2d array that represents a single\nraster dataset, such as NDVI, or can operate on a number of layers and can\nreturn a raster with multiple layers in a 3d array in (layer, row, col)\norder.\n\nThe apply function is memory-safe, i.e. it applies the function to windows\nof the raster data that are read sequentially or in parallel\n(with n_jobs != 1). The size and dimensions of the windows can be changed\nusing the `Raster.block_shapes` property.\n\n## Raster Algebra\n\nRasterLayer objects also support basic raster math operations using python's\nmagic methods, which supports all of the usual math operators. Calculations\non RasterLayers occur in memory using Rasterio's in-memory files, thus they\nare not memory safe. For applying computations and algebra to large raster\ndatasets in windows, use `Raster.apply()`.\n\n::: {#a90b8434 .cell execution_count=8}\n``` {.python .cell-code}\na = stack.iloc[0] + stack.iloc[1]\nb = stack.iloc[0] - stack.iloc[1]\n\nndvi = (stack.iloc[3] - stack.iloc[2]) / (stack.iloc[3] + stack.iloc[2])\n```\n:::\n\n\nArithmetic operations on RasterLayer's will return another RasterLayer. The\nresult can be coerced into a Raster object using:\n\n::: {#0ce834ce .cell execution_count=9}\n``` {.python .cell-code}\nndvi = Raster((stack.iloc[3] - stack.iloc[2]) / (stack.iloc[3] + stack.iloc[2]))\n```\n:::\n\n\nArithmetic operations are only supported on RasterLayer objects and\nnot in a parent Raster object directly.\n\n", + "supporting": [ + "geoprocessing_files" + ], + "filters": [], + "includes": {} + } } \ No newline at end of file diff --git a/_freeze/docs/guide/execute-results/html.json b/_freeze/docs/guide/execute-results/html.json new file mode 100644 index 0000000..a251617 --- /dev/null +++ b/_freeze/docs/guide/execute-results/html.json @@ -0,0 +1,16 @@ +{ + "hash": "1ddec99dd2cca1a0e802081725fd4c4e", + "result": { + "engine": "jupyter", + "markdown": "m q---\ntitle: \"Quick start\"\nformat:\n html:\n code-fold: false\n toc: true\njupyter: python3\n\n---\n\n## Initiating a Raster Object\n\nWe are going to use a set of Landsat 7 bands contained within the nc example\ndata:\n\n::: {#d5219e67 .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.nc as nc\nimport matplotlib.pyplot as plt\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\n```\n:::\n\n\nThese raster datasets are aligned in terms of their extent and coordinate\nreference systems. We can 'stack' these into a Raster class so that we can\nperform machine learning related operations on the set of rasters:\n\n::: {#9103e529 .cell execution_count=2}\n``` {.python .cell-code}\nstack = Raster(predictors)\n```\n:::\n\n\nWhen a Raster object is created, the names to each layer are automatically\ncreated based on syntactically-correct versions of the file basenames:\n\n::: {#a9965773 .cell execution_count=3}\n``` {.python .cell-code}\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70'])\n```\n:::\n:::\n\n\nColor ramps and matplotlib.colors.Normalize objects can be assigned to each\nRasterLayer in the object using the `cmap` and `norm` attributes for\nconvenient in plotting:\n\n::: {#cdb75bd4 .cell execution_count=4}\n``` {.python .cell-code}\nstack.lsat7_2000_10.cmap = \"Blues\"\nstack.lsat7_2000_20.cmap = \"Greens\"\nstack.lsat7_2000_30.cmap = \"Reds\"\nstack.lsat7_2000_40.cmap = \"RdPu\"\nstack.lsat7_2000_50.cmap = \"autumn\"\nstack.lsat7_2000_70.cmap = \"hot\"\n\nstack.plot(\n title_fontsize=8,\n label_fontsize=6,\n legend_fontsize=6,\n names=[\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"],\n fig_kwds={\"figsize\": (8, 4)},\n subplots_kwds={\"wspace\": 0.3}\n)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](guide_files/figure-html/cell-5-output-1.png){width=679 height=342}\n:::\n:::\n\n\n## Subsetting and Indexing\n\nIndexing of Raster objects is provided by several methods:\n\nThe ``Raster[keys]`` method enables key-based indexing using a name of a\nRasterLayer, or a list of names. Direct subsetting of a Raster object instance\nreturns a RasterLayer if only a single label is used, otherwise it always\nreturns a new Raster object containing only the selected layers.\n\nThe ``Raster.iloc[int, list, tuple, slice]`` method allows a Raster object\ninstance to be subset using integer-based indexing or slicing. The ``iloc``\nmethod returns a RasterLayer object if only a single index is used, otherwise\nit always returns a new Raster object containing only the selected layers.\n\nSubsetting of a Raster object instance can also occur by using attribute names\nin the form of ``Raster.name_of_layer``. Because only a single RasterLayer can\nbe subset at one time using this approach, a RasterLayer object is always\nreturned.\n\nExamples of methods to subset a Raster object:\n\n::: {#00bbc21a .cell execution_count=5}\n``` {.python .cell-code}\n# subset based on position\nsingle_layer = stack.iloc[0]\n\n# subset using a slice\nnew_raster_obj = stack.iloc[0:3]\n\n# subset using labels\nsingle_layer = stack['lsat7_2000_10']\nsingle_layer = stack.lsat7_2000_10\n\n# list or tuple of keys\nnew_raster_obj = stack[('lsat7_2000_10', 'lsat7_2000_20')]\n```\n:::\n\n\nIterate through RasterLayers individually:\n\n::: {#0c05154f .cell execution_count=6}\n``` {.python .cell-code}\nfor name, layer in stack.items():\n print(name, layer)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nlsat7_2000_10 \nlsat7_2000_20 \nlsat7_2000_30 \nlsat7_2000_40 \nlsat7_2000_50 \nlsat7_2000_70 \n```\n:::\n:::\n\n\nReplace a RasterLayer with another:\n\n::: {#8ffa02a1 .cell execution_count=7}\n``` {.python .cell-code}\nstack.iloc[0] = Raster(nc.band7).iloc[0]\n\nstack.iloc[0].plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](guide_files/figure-html/cell-8-output-1.png){width=499 height=413}\n:::\n:::\n\n\n## Appending and Dropping Layers\n\nAppend layers from another Raster to the stack. Duplicate names are\nautomatically given a suffix.\n\n::: {#3c34de34 .cell execution_count=8}\n``` {.python .cell-code}\nstack.append(Raster(nc.band7), in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_1', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\nRename RasterLayers using a dict of old_name : new_name pairs:\n\n::: {#4396ad2c .cell execution_count=9}\n``` {.python .cell-code}\nstack.names\nstack.rename({'lsat7_2000_30': 'new_name'}, in_place=True)\nstack.names\nstack.new_name\nstack['new_name']\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\n\n```\n:::\n:::\n\n\nDrop a RasterLayer:\n\n::: {#42702d40 .cell execution_count=10}\n``` {.python .cell-code}\nstack.names\nstack.drop(labels='lsat7_2000_70_1', in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'new_name', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\n## Integration with Pandas\n\nData from a Raster object can converted into a `Pandas.DataDrame`, with each\npixel representing by a row, and columns reflecting the x, y coordinates and\nthe values of each RasterLayer in the Raster object:\n\n::: {#d65fd523 .cell execution_count=11}\n``` {.python .cell-code}\nimport pandas as pd\n\ndf = stack.to_pandas(max_pixels=50000, resampling='nearest')\ndf.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```{=html}\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
xylsat7_2000_10lsat7_2000_20new_namelsat7_2000_40lsat7_2000_50lsat7_2000_70_2
0630534.000000228114.0NaNNaNNaNNaNNaNNaN
1630562.558402228114.0NaNNaNNaNNaNNaNNaN
2630591.116803228114.0NaNNaNNaNNaNNaNNaN
3630619.675205228114.0NaNNaNNaNNaNNaNNaN
4630648.233607228114.0NaNNaNNaNNaNNaNNaN
\n
\n```\n:::\n:::\n\n\nThe original raster is up-sampled based on max_pixels and the resampling\nmethod, which uses all of resampling methods available in the underlying\nrasterio library for decimated reads.\n\n## Saving a Raster to File\n\nSave a Raster:\n\n::: {#beb7aef0 .cell execution_count=12}\n``` {.python .cell-code}\nimport tempfile\n\ntmp_tif = tempfile.NamedTemporaryFile().name + '.tif'\nnewstack = stack.write(file_path=tmp_tif, nodata=-9999)\nnewstack.new_name.read()\nnewstack = None\n```\n:::\n\n\n", + "supporting": [ + "guide_files/figure-html" + ], + "filters": [], + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } + } +} \ No newline at end of file diff --git a/_freeze/docs/guide/figure-html/cell-5-output-1.png b/_freeze/docs/guide/figure-html/cell-5-output-1.png new file mode 100644 index 0000000000000000000000000000000000000000..afdf15a6069a45b73b58c54a10b5513d4ffb9af0 GIT binary patch literal 613660 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ⅇ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

uJ+Kk(W*NQMJVbD9=~e28=vR&<$ml1R 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

    5MS;_&FYx8jbkj7WHS7cTxD5{IWS@vZu-tooZ+y zAX{dz_lnrWOw|tpqKCt=oW@ItC$)9v;2Q~B_!d@HTgh zKiweLJ65MOuymrmsoy_owx*2ha%j?>XJ!&2_DL=!Uud|oLO zJIO?-%w|p#$wVtgiVGMfFx*!?-s_G93(dq1Zc43cLUTE>rWfL*f?I-gSSuJnOa5DS zd+`31P2+hr@@VvC9+J$#x=B||f@$;Dt&8g_%O&}DsDJ7^1<8~A1!$WDrq-QBFTEwd zyQ41ehH`o`_79m*{PKW-_F}E?>LyQWy>xRLIzJ2+Q1uEGr4Lw27NkL;%Ys&-!Lzt; zqqj~Nwa{6HpK(&rL5_7MWx@8Si)K8bjV(=Wg~rsUq4sD*?qx#H`L&I9YQJ;gcN9YG zBJs)SsJmWTUU85aGnY*j?|!IPp19K8Y{n3y7LVSl6${+zyG^~hE(@*Xh0=uM?kQ;0 zpS}KZfiXzplW4Uh3#LRjyJB8GPk;4jE7Ct>oFlm4e98BoKVw7D)`JK@pW_$Jxjgd_ zeV8wNy>x$9D9DY}FzYOr=e++pC~4NIP3Dqg+ui8bdLmNv%ucrNtPv%7ny%1>0N!Ez z)kYZI)g-I`^SLpssP?Zu-0BHL?m02{6ymwF$cy}LiNGl9C;Z2-4(bfxwhZuoQSG$r`H2fc22CZF80PtnleN*&Ds)-RmZnVJ z3zQHPP~ZI}8&{S@Z-zZ>#xx7Yb@MjQeU*IVvY!3|07lL(tUhR*b|XBphk%CY)Sc&Z zOu|(9o07m!EKyM7s6{e6`|Vi|%-Bg##qlI4zx)xxjZ4|>xHj3jY`_7p=zw9WVwpUG zlO+hHp-XUQH@;!rN7_;)OVLRSd<1GE&N_sVNb80Ckd@7Ab^ZSssedOb{bvVM7lD zu`o*xpu%`XSpoj^XjQZqhkDmOmbZsUYC=X@<>~1zb9O7aEYUbPrzmfSKD5+{jf*4` z?7bl&+cf9_2EF@10BuqdW`?9pjsKNVrxiMzz06XRK{Ud*_U0s<1R=24@%(9M7uTQ& z6@x$1uU!ojkFrmx^ogc;AI6F;9Wjs7exne)81!HGHq}o?1A%sa=&m9qXnM-X-eEG= zZ-Ae_ezS=<80M)S!2I}H1TnJxhBGGhOV+iCyFNIeXqCIHQ_op&i0%~%8$**|9pfD* zJ)?qg8dc2F1ZG;FrMwLORP5#keup8}a`He0%P>{K{s+)SwH2N-NV>ZKr$$wV|DZLL zV-@GeFNm{JN$xw}!;hAC=5v_e%0D_kwIuFTp;kL8ue4X9o-!$cHd$Hs$41DfMHFj0 zJc7OEtDo@mt8B6&8H(zFYvtnbno3F9OAIJyn3olH%j19K4NS7%ZnBW^7qX!G!=*#l zWDisg>2LVbeBITk(bZgQbSGbZpU4x}PV*|ln2e#Vo_0<}()IJj;%$4VlC}5nHcnW^ zB%oZ#BQFnTi*wV|0~Y{uX@5s(C?Y|mC!1>9(NAG#l&w*um9>V26PBLDy|hdp@irv0 z>1}PG0BC%LS;4RsqG%DU|Ecv=e^i~9zGOjE&R-p|HVuciHL0jdt&R#3xko$(y}dy- z0w}lcMs`XRU{sgT#2ou})i-+|GwfFBUC&^h9=&$;M>;~jMc4!AF3uacD|;v_e|b-m zqXN>lU*KerZ8auO2$qxomDC9?4i`)n3}7E%#Bi;E#;2yS?C)orm#jgzK2v|%d7DMa z;CTsduzUp17nRTrz!iZsSw>2xF$6{u%0R5;hgao@^rC6q^Ki3&;?A#73u{BCNw&#i zLdMjB)2VtmdFaGUDI1)09*e)$V8)5-HYZVWSpCL}>J_OnmCb9CT{=^(HXPINto#?_ z3Y$ujOi@{k51Ygi0aV>SKNwQwP7Gcl7`n?76{OMhP>6Kb;?1IucokVAL`*YeQqIgtj9}f{bNM>}gpSj~4)}Wxhz@v3(nc6g4yA+hE&rvE|@7`BXmKxYlM=wfb zrg`N=Xz{{~w2CXC>F~cV9@b^5k(MSd>?RWvTaIzxQh&XES%?{0d2f+&XQ;JwIq4B?(j>iER^R>T$-tD6 zto+?XZ>fZ~Ay@B>Jh^8i8AHx7N#lUBUqzem5Zv&FVYy}W6f z$e%ecOzVxU5{N$5dpg^G5_BZ_!yCBuF{9Fx6XRRn_wY(Z9u%^-eY$h?YpF`2&6<4S z+$KFNRC}F+%-QZ$GXgH+Xp9oez?g8WSJ~d4@Zb1%u>?tSW>JP!(5)G76_9jg9hPKs z?|ELcCsiu$o?)YmfHsKACYj^~8Gi6O>!%p*^i(3b7A-C>7&t*tB@=W@JY9s3hPjzb zD52>@pro)Ih12jh4xPVpN61Bn!x)hlEH2o+Wfc@;q}xy$oqN}rw0!s>l4Cl`=m~!o z!#9N$TpS9JqTsQZ9y@`?jOxo2ONlyhQPjbLqV^`R>o>gnWsHN=8TO-C-Wn&wwYZgf zwmQO5O0}d{lh_ZGx^nwk>$6I)%lNOLQHBVq2(V&kN5KmjNFIzk7VQnUZgYe zZt0>dg91BbhG4Cbbhx6+VKBvB+a%h1a=t2TVRlOt6Ax9@q}-;f+SjV+Fc0QXt>};r z#JbgP-G?}FDJy|Ij(1W{k1}5kWU5OPC`s!EZ+Jx^@L%^MnhhFGF~~l>3ymyjWAn`d z`(~Cw8Xo=j+w7pVfCTHYAS$@`sy<7zY9ZX2Op| z*@Q4-VFUa*>4CNJPyRSEa-~DvnIeUpKnp+?R9JlCvdH}laEcAy3obLBPh~A#KQ}Yh z+u4|ay+!qBW1g$gCsK((kS~QcfyX8iH2a9-tkblFaC*u9u_~fUD?Ig{=8-v!CzgHnxOM zd*m8QX6nZ-o%g+%dZk8z!xfF;L^4_ue(jU8k*vTk>9p-)oXRmBc?J47;~hq3l+FLV z)-TOQ&H5vsgjKdi@Aq+?SthGUf@#+Od_y``9w#}L0sQn!%FvQFC`D zu_*sk6{{@2=LS`;{E2GZo?LOEMrbNNzeb66g*<9H1h)3KQ%2YJT_|p&&<|5tlo8dT zloUEcl?36y>Nsr4VXds4R7FA`9UjG2+r-|>_;Fr}uQG4iWT_45^UuhWUhs?+>xX7w7;;=Ey0I;(&5*gmj?YJa19erf}0ZEwSMw8N}PW^ zI|Zhu&Y^JBa!XcNZm$f!I&kJF)!*T4c^n=;WiRUruU9-WK+Gr$lt`TWtxb&5uE@cE z{Jcb&No*45`Ez!1BlITB@B0D6;5T;BO@t}RxCCt!-zS})UmCoz{lZeU-r7GaYFTnE{@s?3>g3e#`odzEK2P$}!7ghQ(J1k`v2P1yx8i5aX^xJ*r`Cr5 zZ=|ntCX|Y&ZEN>^EQ9gqp zt;An|BFSRc1l#vbO{lKvJbg7HzDad)%=dZ)-M2XO&@`z~m$xR99_!kmweck?RHZ?rK0LRNEoKy>$t7nmn767q70HsS{Jd%Q!YwG z#x!#Un^rUkL)H{<+E(osJZ&5UnR%=9ALL9+d!)jWTAf;%J-Q-h4?QwxY)c0cKb+Qp z+3`G<7hmT#WZ2_$yJ^Es;~^(?kuamC&jOzgXB#gg2MRiQ{}N$FvgwnSyp1%`iNnGY z3Gnb`q6+rysG9xmN-E8CoDJ-9=IRs|b7GFm77IOlbDqPC0^Mtz@i!hkw6;hmNrue& zm+*2;AN$h}<`n+h7?HYHnRogEWmDq)qD}|;OY*af?nh=vvL7MYoR+a7DH|8Vi&T(g9K0p>{D8y!c_c3!SLDpdmyiV zkHc?|n7Q{rf8ntrMNYO>JAl^}H2qr)(S7(YqK!~VdJmFb1L343E26*X@dZNL7dOAD z9cDpg1mvjlx`+|IR-}0hekRrYBmAAFJ!e7=v+XA#G(7sHh>zO5IJ0v&g;|{56EVa( z6Jr-5?}coXFaiAkL+pIX z7Y~hxqVDuIorVve&bLKf>c>7Tg(?RAkzHRZZMT7oo=PLa*QfpMDyBf9QlPA(vnKGurRO%|Fx4%@fDObMc-b63dEv3#7$gD^?)Wws&=P(oVnj2Q}3GR|Pb+eai9TMxR= zm>3k5={+@C{dOr)32JG`Up*BjJ_FD4QJ5{yjLF?jb}3?Ff5Jq$%9CS!u_a+Btkk3V z8L!d=!)xCX^z@pOIqwGr3`6Ci>F|qy7<-KbXqdGZeDt3=UFl^RN>qunqj^HAPw6$} z9eH>S7`ul45G^h`@1n_J z0mzBcd=g8S*AYbfYNp2u*=q$O#GOtR^^%y?%QB>CzZox+a?0Np^1@Cbl1HL z2QZ)cGSLLNYobr^l5!~pQN#gF4>m9-s1)d8%G&r@yj0p2Z14YnAtI7-{!na}%Q4=q z&WDrUt_QCdOgKu@d^M|oev#Zo@{e$H`7`*{D!@75GX1~>=-huiC!^t(=N z_xWKa<#9R;6)SrUB@>hmkZ#QipJMsyIFK5_<98Ds&+qM8z^tAg44fpp&zIol@-!Ij z3ae-+%n&dK4LXuAxmjm0(|xiBJidZX1c{aPOp%#Q2MOpxGVT?XUr4E1f$nS==qA>= zJ^T<7Oq_Hl+u5Bp8HdSy%L8kRj_H|}C=eTg*~#|-nc5EW_t+RT8F^=yo9Mt>XBN!I>_&AXM;xEBA6gx$r0w{J5lP~N`42EAD&?=k+qk!+X4|8*) zn-ESPob34p0>wvxn33x`YlNTb#Hlg4@Vp3qtq6b3c8^pEK>jt;G1W?>GW9Q31V`9X z;6+66q)qDxfskm}uEGRE(&IOt8&`bRfN31?nTP+4P8B;a7fiA5ri6+GoT9I8?3u8R z&HXdU&g8Hh&Jl>MGKcdCUU#D!-Ha~e7S&Q%dF2h|ijw1(uebTGkN0t_lqo4#p3X-> zc%n{aun!uSL^EZ_2Pk>(UoV|FFns$T=PUBhcBV~3F+wg?E9C1|ZQYzTra!{mBz+b*S zd3d3w$k7ZYEQtBOg2{BBay*W3H3tr$-TZ37OC$W1F<;zun%t!6`?)Oo#+Bnhs+4C2 z{02KTOZYVwfNBQ1*i(ML@HMJp zE9X-(4{~M-b$t~rbEHFC{Z_{uuN3z^f{iozdvNDRwPX0#q*1o>4M(HI|2HQW^v@;w zUq0aX)WM^r{X8eH}Me`Gk%w_c^@O^a9j5ROE!ExQKqH2e&GX;bcs++Eb63j zR5lWtYJE*ZcVaUwI&66u!9{VKntXnd$?Y_<1Ub}nH$&(;lF18)-8d1Za%3OrQ@&_x zK$@gIRGSO~xFWEeqnM>a2r)R&*zqoL0D;IS3YBaJ@eT?8k+cVC9VH_w1G{LcaR`Gf zL^fn!&y{ctUTee`iaO){3Ti{GIsaW+{zYQB3X39`C#?Pee`Xu^2d9^G zQl8Vybv^h!0mu_4w@ASHrlG&wNtQWG`?h2tJgLhbsRs!M6G6Y53A;{b3Cii%VTINF z^*4Tv>KwsE8oy+-AK;f^hw-f8$`qQJWDvr|=TYBa@0h#?BThrC;59+I?g3d;j5~SV zEOA5O6SNGvHn>8@YTdsWC7EK$7s$@>|AJG(w(!eA_$0To z{R5aR=-yelWg|hKjj6t`QAs-pR3tpx;omP^1@L33$dF`qgaXGb`c&MH%y~+%K;9hR!B6)sKR?4%9fi;7cW7r~ zzgGsIcq@kToILjXSZZ1p-DLESi%rHkB{G8?lODq-;~Q*Fy-v8s=+%t1)W48JkaXyY z-D3G9zF+USOr!+`x*)v_HU}jH7*MB1p}4g;aU;^W+?jFI{~^G?OIH-;;=!#U$p_9-q_mw5vhv zNq6OLC?Lk(MU=1U-2kEU)H?e3ndVJFtBk#mV-jL2Y`GTcNTC2XOR~9kAZ_84m#cckHwcT%`~dfF|&0 z1w8n%7V&ca;aLVz(Yfo%(?U1=A5k#oVVkyz8nBLf_Ae$dwU3{vWUW7IJ|{~F?-BEG z-%|vS!G#}`Qy6AbX~Yi9hlWxfz4T{xFJ&x}$XtssY10&Osi$}Om~%j)NP>B=7yge} znCRiJ*+=}<{lE5+yWPIqYr-7P$TeXKH^kNIoP&PA@aRPxBl)%l2R*|CFX|q8WN2J4 zHLyO^pvxGQO)?$W`-_`R);*GC1&zu=lMS_R7&}IAGTjc$@?ZjQ0sn1{ZP*f;a#(Vv z>iowpwou>$0r;IsN*e}BUmDtCtm&kiZ;Sv%-?FMdw7r9>x(=V3L2UDTBa#=pQUP#;8%u)JVX1(Km36Dp@n3zk#%3SR%VJ~SK3M@ zck=?%G0dsdL{i^HzxQ}9Jm*4jqm;L=&yGsV;^s}~!?Dy2 zbg%_j@g0NTx?2F2k<*xx+5xSQGIR?ue?v7z&g(A&g%Cqb#sO@ha0IZ8)<$&*E@nV6 z+Cod#WUacqCe{RvNNq(Gv?ON6s#T7SAgG{B8|#{D+eFA8Z2)eLd`#kNxBedC6KRcx z^2$4TbC-O*CZ&Mki{!XBqx0o-{hL|s(`dtTM}0Lo*U4l{p6`kFXh3DOJuURh?p8j& zMFu>|?xZGcy_kzbl4j^~;jx+?cU12B8%+W#MMfFw+^18OqG!L|>k1R&fNy9p;)*f` z34j=_^gZPNq~)Pzu-0-$(W)USo=8VpjF)4YlO;zRCUTqJ2f2f^dZW zj=%qaVtft;IJm5Zo&Dgm`$A zxFQHR0B=mcYtur*jf=nZMEja6TIX)>x-8)Gu8d3`*d8Z0ajN@yU4@NwR(?`}(wtG$ zH__=Rnx%2d0|L1^&G2+}J-1~(gp=?{@KATl1Tw&HU*5O}4!XAwDE!BNHw7FvRkyT! zPE95L?^iS0#xVh1FDd&`KVb0l2QdhIx>B}xXfx8L-bo1np4Sy31XBMRzrw5;nq(kK zJ4qh637PN(FM+GgoulR}41n=)600?%Cc2k8X)6x9ZG3{V)kv7g1hadxDABflVG3j3 zw8*C%eE2Sstx5E#vr;z+50LH5EVJ^RuG?@V8Q|9zt?SMj7qVf;JR;0^=q~zfh$JYs zYvH5!DeyJMcV)Mx z8FpKxx{@Zs4ly;^x|B#7i*fR0gD^xjDT zz92j@{croVsL4^Z4^M>eZ&RU$i}KHhEx3Y203UlMu>tMYIs7=2Gs@5qQkKirKURY8 z5g*;U$H!7b>qya#(v}mbqwSHt8BD@PdWw@2W-!GyU5BpqevUwn`e}xtmCb6u5FnZ+ zgR_U!7`zKU^YTPV2sx=_J>J1*uoT0%OWm?W5{v>Xer4PiSnJn5eA&EW>|5|pVPANm z+_&KQW%lyL<#n~wFe#Hel1FNZP*j;3>UN&xH=1XR$P(=ZBpy(~l{sTQ8Mh}A8xiXp z>unsR7@U*0A(e{jm=g$xw2xL{Y?bS3F8xK+;bok}J*j9mJcx$;qI}&Wg;F)9%oZ37 z+QK$0_9XF%ID*gz4CCHr1kyxl4H1|9mlpa`U*3(_@^c}O&^43TnHz5jK^y>(f)eUF z_6ren6MUtpfWX7>+_5EEa-=LCtv;!CA4)VTXY?L7%JNP$fpZCZUbz)}ZDg`5O^dk% zJsU)^nMjN~%sM%YYRV=&OD&+F5*eSfj8>af^7Vzos=~bT=^8l&lsy&_}gW@E}s&BZAXMo%e2^D;dO3k7@uo&Wp*8nNk$b< z7>sRIKWwmn4RIy<`cOY(K&C@m=nV*je}A4?g43o&EcG z{1>Y`KVBQ3w)62JhNoC(%nJ?m^blZ*Kdh{*s@vNin_*f-`bI_pqwW)Y71T*Y6T#h4 zJV$7enKRt(8kFPoY#M2Bad4|ZgJi%f3`hK=ok-ph0;*Rq%MD?lF?g?-HWWC+?=w~h zTi-R6TyLeR(w=XQn$P$+Ab=!Mf$>YVWYQ5jA1{|{7o`(>YC+6zrhB~-nVM{jcs9q8 zWa%@`I0`=ppxxdjkm0ZS6r^{d#x$501I zmLYNaxJ>qx`MEAf9P5yIt0U!z98S7rNy4o?APY78LPGZ$VRH;ErnVR-4soUNm_)5( zCeG;@0U zN?^1fdLMiFtFpHkQod**t0cH+uw(CiSzexAdZ9KeJTpIaWe~ zlU)|B{vc59MGo=6_`ql9AMU-yJ3d!>E*dw$pbh^M?^YHWMVRmS>tlhOwGAI94Uz(i z%>D15Tk?eIledpad5YQt;Nz$RSPm~|Y8%&I2D-&4G<BGm&as8I@a5&pW9xof%=9;ebv9P$qg)CqX=(j@cX#iyxW^3q~bq89JYBUk9Q zxzqE)7R$Yj3{e-esqau9h$7pfSK9Zl5k{QfS#~XTL?6%Y?7TC&Oq-)nRA2U7ava;D zM8X#KMB43Lpc7c(G%^+sWtpSmiTs6Y`qWuyxlBvcY@>S)z`$(ym5@{{*cW@Pr&dlo zOU=fo&<)klMD(VIR#EWm1Diwrk!yfcOnir`skgzSzNEiwo1mb;s~R*SB)iYIlCx5E z9|Sp29KG`?)Z|Ndu}8AVQF_}u0F^RGqeVEG>FFG?xzS#)YoZMd8?AwU;F@|N875>p zU70b&8D7se1mMLR2pt3Vw6r`~4ca$}(f#S=1s1*u&F-{T{bX#QJDTU1r=@R(#B!0H zqjpN!)O$9~Wi^H)C0$inNOz7okg>?bIaY5c5@q z&M|iH$E;&#sCRk2=>ZXr#bGC{?heDP&eT=_){lf+wdQx6|5KG1!u=P5@E&rYT1JIb5=pj4hB)r3r-{yC6=~avsr)`Ns75G(BoccWtl8Updj^ep#TJYy$ zUpFj?Uhv=mV8fZC)T5Z!j}TQK;zKVAY59YDAr>|HN|cODZjH08CGxhn8q}15)T6 z#`F;OY|(PAp+RsWKO7#s;-Vm?0llSt>`2e)Fl@HB5<@4p={jnnY{R8jgx*C3xzQ>n za8=c@7Oc<%zvv>xx>3q}Ax?gZYxXc+iP_lrYBBvThd6vb_b-NoJeI@Yb+&iTHHGWJ z4@^*4KLwH}rhG^Z+qK^cQ)_f0^($1+yq+*@maW>o0cFbkMdMvmoFgqkF=%f=u2zfC4k>V z$n19MKvr2ef-Qri*sy9n_Aj=8+Y}Ub*Zx^ThtRs(s&M!^zkuvfBK@fUm~WNUp4K|| z8W*L+Wx3c+WVdGjoWez@Jh@$%@Q<{lv`d5l=n!p*k!g_w=40|CRS{_|Kb2N`pP2xXNj z;htzx-bu4Fa&PHGP;Purk2y!SW?#k>8qry)x#ugKRffILXh+PNvJOvwW3kb|83-|z z0L>ESA|v)&497u_gEORg+g22jn-4UHl94f?_^d6Z9HwUxf_m85mCuq`Hv{aU#NSR-|B`KyekzS73 z<1?YEE;|!-K~PxWChF(jwX;JKO$vU^iSof6UV00%c-+BECrF+v!Z3Q8i-4mK7$R*S zJ)I%J3hFYUpop#dZ5wyEIKAwslKrnUKX#zL)iX_QRINv?rRY!BNEwRUJzG zzV+t$Z>anRDN$6E1RISF725Pdr0G~rjI2qDL@OQQJ^k`m5of%J!g3LOf{?WmR3Xau zqAW;4_p{et>$1pC7sp7VxI~g(Bzv;tE(r7ai9(ThDfLJC>DJ5^M@%d}*=lo?G;Tuq zeTJ(IcL^tm9Vsk6J}L5IBeaM<;)s_$TrPjbv@<&11jYZJEi_6CYtyYus0Zhy4G@KM zw<#2nnZ8#=rvx-?ZL8QT1m&_`A#ue13~SX5vBC@ANAUY90HfWU|C=M6wT2~znZ<;f zyPggfbub~ACzgK-C0%Af;7z*7>h{${bVoZ4MD;{XMh=y6_O_Y-`55G^!u zegqGc2FLi!9q^mj6vxYOO6}s1enr2?BThs!)Ae};H{{{{(Cl*`U?Q4CV#~RREErzw zD`XuJ3fepJmE3X1#EAS`*9h19KNUx-3XXq(&IffS&Ot27(;7+?zf51HH0@+ki1RYP zWFhwIFn6C0-&axfup{>tS>6FLVD$=m#zkyR5qpu-{qpYX8I!^$#n&o_{B(!;cRvm& zW~`(g39DM|=kzX-iK6#8AO`n0Kgy?UC3#Do^0Fex1z*nnckKwax14Ip6tMM(Z>%NZuHwM3_uK{o zK#A5M%Y{S@YA=i_FxG*!Xd3rP7F#N)886w8a?G`!W|cqG6?vK(rHZssHB>IcCDk18 z5qq8?hp`~Vw`BXdgm3qoWW@0HNR}Z~5sw~(gc*q`O-^J}>OO;Z#_W%%t9r?m3$9U} zEk;77$VltS&T>I4k}xDoPwFi~i+`6B5OrTS0yF4mgH&uT&xT=iBRB7k0_R50F6?b3 zXCN3_bhH4G1kH5(Q)7PO7YLXf&ErohW8j9?mxiq&KpVZP&y~ zq zv-}5GEVM&*cD;3_f>iKx0+4n+bT|0qDUJB zOTHX)b;Mt+ZvB({Jm1E>5RpI351f62`vKUemf^|6=HtdCm)%US&BAmi1VDLJ)m9$) z)BAuk)IgUJkN<)gU*r6c{>gaYK(OY9SKy7;x$xShFg)8GmwLmgG=WM!0RLVi#dw>H z(>6H~BELnDQ4nc4NBcv)hIOhc7&t1hdDE^a=|zi8d0^z==;p3NmQImGU&L|B&GvrA zV4R|hk;^gJgE6H|pG@A87&cqTM`s}-Q#~WbM}4_BT(9?f^}D4Ve|=?OSHmcL06Qy7 zP+2KCxF-o3xzmP0Z^6}g=K+$0IS7^%2vTE2nrAKAJ1R_2Mj9cjAJgFD@skGk-PX6pGHo}SL6fu-p+yGNGU6L4NG*CRhaqZV18P&%;oyL z*0Q9*c((hr3|SJ6X`hIgaltUC)-|omgU2Y%dg(~hv+U~6Q>?l?EtcrlXVd}*YY769 zBOe0)y~;ekLU?iH&Psj`b={vsSU2~@(FwAUpLIGA9%t{?)*oW;(@UJgwXvc*`1Z|eVtSvGozPVy_ z8`JGf$}udUuX6)BL4JF6Ff2WdZ?<#t%8yGO7*lufE#cC3sEIA17v!CtEibIP@C<|% z2e0}2cy$i+DkkTY&1*^Qwjr4B;4db||1>cvgD*``t;!y{GWYeHkLzo#Ao)C*x9yLB za3h4a>5pP{XuZ@}<7*fgYiS(jSvoqGl_Nh0E46#LJ zkX|Bo@)Y_g4YTe9Zm3Fc_M2YPLw92T0bt#~HQ{7RX4b}ZXl5QdaXkO643AHirl?L; z8q+L*?Ur=zaiNjbxplE^_h`%C6N2F21S38C*k~`xm(ch08J*wppCVmfMUX{kdmociqip*!wyyC*rYwaTX)>U99}Y%&jycCA)boq zpCRky!~+>~nB>{{P8-3_YN77Pr1WA3EULI=k^B#mx5R=dvC@3bEr|apZcHnZf;UJbzEtMVxL`pc)1+= z%e(A?X!LSFxAo6qrIJKj*?Dj0w~j~-^S@b%fQ!u57Lv|S1xnJLfHeww8=A(?hGGt9 z`7Axil4qWzMB{$I8VetkU)^#QJ`*8glfjRbn3|3n9-{pa>>7g?k+bhRL^b-&;wsE| zsAg8BNne$*P1AP#>@Y3RI^UoWIWSZ9@G-BkV#{Y0U9=mm9B?3-p*4y3(f_FPB!zeQ z-UQX@`L4?by;M2Osn^C3*o+U~R}9_4C)9^4uqPmV8SK`e;olW4lNtYMJ8Lj5m^TK8 zkK)h=7w0h(>D1bgaHa4Q$$NlP8y-6Gl1hJG905mWYb-$}!cnDgOa<-c!K$WOb*#70 zKF`hkfx}f~wH9z6ht1VnrBK!606UJqfJSswbH(AQqEch5Jrgkjg}KYwI{$!u9eeG= zr;PnEU<{IqN(C?Zj^#b7{^b!RnS{9{VM)N1e*BeAf@9Qd>;8k{%9g0#i%9VM7PK{o zm&_zF^(m>@hBfrZp@A*`5Zbd2Mnzs-Ku9n3y83U`GZ|f~xNKm^;O@|4<+r(4-LMNz z6CHj)Ad(;QIaldT41Tj6PH$#Y2*BPwAiwP*OGFSn*#EbRvl-mrcSt2?P z&i!P4+uoz^z*=W$8G_giPaUtJi@ZF)T|XlSHlxA1;^%jj5$m#1BGG-%5K?#NEDRx1S%Bg4q= zxIjgJe!8m61a|VotEqsr`>&N@?6lBRK=$lQ)95AOHf1sXjyWW*yK0c5e$q5M`ijJR zjU=%qD{;3ISszaabI{#5;W+PR_-2U54@ANoNb3D!7~);^m&S|%5AbN;SM{Opf)hY~ z^9j%Nj!cmGPR?!3|vXe-D z_*{t#FfE8CZJT2ZRiVTuOBBrMedXJOCSo}GBk^Lw3Zsq#H-2})RVS>!TP}pgv%#xx z!v1sfA1F`dR7@0UiXjUf*4c8r%t$9G5zQSyj&xl(MDzPjHp0<2O$zSPmcK1voD@4J zd!?fv8J|MG<8F8ix$wEW*kWB7mMyE;Hi%wt3g1SoHIRFh4{SddIA0j0UwooR#DWh# zajYKDJNzMZLhn?=aNlBtHZX5lA&wd!|BfR()-`!#b8IVbi2B9?goV)}rol-%FZQud zH!GclTGX9**PraSi#t3XI=|dDEO&N3a2{lLZhUk))lZ z!0UT~uvxMkrtOTy21w{kRGqP4<y>+Mc^u?Ki-bU~J(qU}?<6Lwje=0n5G_zW3&)Ev(hn)de)-`why|@F50a8+ zONq+r@k-LrHR!&OeoKpN^d(-(jSGC-0zm)y!kU)dMv`{_%b>2D2JmLM--dj+MSMJ( zcxDRNqzgcR6NbF2-qa_}TbLxmpFBqF;f5NX|8nJmtLK>Im6e;wtlq%qGprYE)=$5_ zG}^xMOx1#k$_Xxi06g#bVbmlvx1RIho37oYV{eP#QFurqlt({0_IUWTXm6* z$4DfZ20nz&*T1j7)}?y*6B&K3Dmj!p7|D>T9j1JNO4thhuJ+)*|YNIy!qFBK;X32i6bGibkO*DH z{@>=Q8qM{skES)N`Gfj_ha%eA9>GL6Iq_F&@5fN#N*|Wi&OT#amshvUo~*Zdw@5#5 ze9_jTEtk!FR5n6ndhEj4BSRrn-~$*Vx%B1< zWlan=Q$FM}P8j-5(R(~;yu z=#eE1tzD=95&DN?T27d}-1-N_E!*=)-||*ve40{1_$KYO(vTaEg}$|k*M$L!Uu|?4 zZ(VJt-ur50o(*n}t_aHxWy))=cJ0~yoOUZToZ(oDCx}s5Br?dbZ;Kvy_6-B%#uf`O z_zpa@WMaA(f)Y*u<{UXlX3gc%8K*n^v1`sKWrTQG$!&dxJXw1^I^oE*Ck_!8y^BE= z5xkgys~{A+6k2V-Mxn>3Kc1oCHs|-KeaYbt6e1mf%4{Phi%jgoM2B-YQBnZdhl=*qSqfj9#T5IW+(L2 zxjYT?lc+@4RT}O@Qy0OTG>gkj_ztZcmM8QDFe0x50zHE*lp})j-oqzdLC^V$kGO`S zm%5AtJhI_w@P3ebcsPg0K0J`VMsRxM!Wvh^N{jAD57IX>g!>sucHt-ELvkzW`17cG z^P!b_N#~ZMOzPGaV}iqPj=pbx(3`M+mOq;cV`v%|JbC_zCM%Fp1Dg2rktklE9*vhdbAQL4`Shl48L zNZO+l_lML$MtPCZvGFfG)(S*L>~#NQnfA0#MC@Ku=JpFu@67lE!$HdsBQOzNZ6{}> zq?lnNILN-wO3l3%12SUwxx=b$e7JU;s#S*9@_}`54Ln*Hxw04JEfkF{IBnlw(#noC z)cNZ;Em*85*^+Ev7DZlQ;)x?p^G>*a);P|~Upc42@MEE>;5U24vL&6l2Yj=->T6QY z%&t|EGma{sRHIy{^y#Dge-EkJPUOcVK5sxVd5qK0eyR%~)12>7gal*FtPh2Q|w5FWAk_ zmI&+5%81&`z+3ut{+Bm=BFN7G9EZcPVX2zxfRSEUX074`CBiDQq)sJy0-Unj453ZE z{!*K%FphmwnOdM+{eB8&qB`*#C2p7$r1lYwk{P|PJP6MS4k8q2)7B+aff6f8cvE$q$Z=e zer^{yplSQ+7R33)!d6WDhtCzo?&Dtv6gd!0PPyxlMv!5gFc~`Y@P6&zR|Ar~pZUM) z2^b?m5d;b3JsEyG+`m|#8s{;$RX&KEHC>CGK6ExYY37m@i+`mMg<`yqVN!}5LXR6zZ)=Z);9mY1)jT${Pi;5X(k-)MEMWL3r0 z^JTwE$_4|(HoHINfHfh9A`|x69om7n6Fxii!yi**!w_=X?3P^*v+8a>oetbryku}b zTD?QcA(?C;pHZUJG(qIoB~x^7I(YpD-D5FD_YcxsccozgIE8>pKP zx--)h4!hw2WW$*Gq&KQ8C>(d5Qm%!J>&udc#A(6qJX+~sB#|b8{6q5#BPoANS#?W2 zD?KIM!9+i2tI}kAhJ_V5^Cfz&6OkSD!(NnzrXiB2;a8m(L+R}gGOKc(!ns%7ju&p2 z$!N#o2lJiuTmvW*Soz<628$Qe(!|lZ+@*~}IPc19)s_(SX5zu>$pQ{sUZ^Jz8kav0 zQ%0R_!*vx`xeFW*MOA)lRyn?Pzr;!dd#o}^EJ58e3l=NJko!~>pMDBQ$;%5^Hy~F8 z*Bg&fPwb|vm$)dKsLb^9P)d2W(IhM0nmHEnr%c3D@_$0MRr!{#khSQ&t;evrB6nG? z-IJ5Zx-Rz7jxNm_%cO<&c7=7rN|^kM5Ep@aTgpTD7&Cq4Wj;>)2?6l#)cg~5`Yw6V z93OM8W-q4cc69_klnz_6HEI=VXxk$Fo|QDR<#9*gTLqJxnY3rQyrIGI{!ni2QlH|{ zEg}`)42vnE*Vu(2tyU;zDT8>}e*BPj3*JLlh!(1+lld+i(FqTsSIa~STVNKhOR2N} zCfodBm)UmZ4}u}fdb=~tJ_capHBRC~9_&N4JDwi*N;QwyuLGN<{*mvgm`%c|bBcPqR;^d!s+8q1uHO)&=ewlg=(m5Vpm!O(V zX)05`J#)k{Sy_2^Yq$EnALIdz_-2BV>4dk(cX3vYo5T^5issC^;19ilV6NgxrKalh8fE+~2Og^2G( z^_Dk4_h4WK-Q{_kD8%`sJ49Hrw8`Y~?b!f%n6VE#87Y=~(?B})A>t`3uilwPqhWY3!VR3R5Ou}nf#7#6bNR8B-sW?TXi?lxo5|X z&0W)z8RLZ#kM+E4O+v?*65^zTOJ4u|-1x|_gQ(8L(txB;q$^r9^he?td3z^AoFP5t)QS0 z@K-KsJL!H$iI#hPBU&g;)j$U~Ue8I)S9G;%dPhl2V2MztGCw|_LsnZ(DrHvhPbQdy z%S$?6-S9FuP4-D#^tUMFr2qDpQhnCE$=~!Q`UuX8lSGeBR;WJpdtZA7&GHycJ$v~L zekBCggz)-h-25!L2Kn#0_X*ZM6R67Z_q2*ZQ2nC#H!b)?qg&w~t$1<^3hyQDr$6Yp z{4iA%Sis3Y(hpp!aVIFg`%Ft0)U#q&DL1r($d%f|hxICYoWmCHx12tk8_(1{!K_zG z8iWFrRksuV@Mmmp;7we*`ESp-=_xtZil!k!^(c3LvERbN7;Y;zn1AJ?zW4_nQH8N; z-ykk=<$I>@8~{DQQ4NhddX@(p+u!`yzFbOQ_4JE!qOO)F<|pwWUP!upFw~*C0;iQx zH(SMBWemL~brixldM%t_Ca_kCe3veC!~VsX_lCXW>-WNeeQqVp&Q=(?xN|@6*FY&_ zRsM|BT!KZ^$)(N_Qil42#do54h-}(Xtpekex{8wN0|CyI+^gn;7QPWWx&opQ{yrd% zOOXW9=s5vgHL*aWFlxByE;&EWjAJ$Bi~hu6Se*WWj`Z877WI1EMXJ$N!~I=5N$ex{ zwvKFC1SOw9KF}c*{h05sQpnp1d|#Ls?#{y(@HpYuXj|EGEC25;%H{n6HU#Zow8YCo z$JT*B+MHN!nV|iNmchN%Db<+~ zRbobZD0ph%*I`@qj^e=ZU;bv(-G^b{XFr<9v3mo0kY^<9 z+UVTkn{u2&I!vGHT*YGAeWdQHbOc2@@>-d6^#}T_B+Rq3=`@;`LW5_kvUz3T52G7K z_zQs7I}J7Z<7i$xXZ?Wo*B!Zbk3!`G0$h=Ry?mIwbTyhR7e|5D`X`z&{nb>^iG!_F zS{3F;tg1noeN{z)sqZaM`Ck_vwDdbgllA|YT9!)n5b85_D;#|6)(grO8Vk0e(BU>z zY20DL`;%m1aPU1?3*uO~K_9$XkF2zNhR)bFu4diog0%9jejx|~l)fWkmaX8aD>_wi zxXF*s;K}#=;!(@Ex4=U&Z(;SpJ$2Ku4By!}*XIPf`P&UJX=DqC1v!0JAsaz%8UM4S zuI8lL{#5Ztf1>A$#BaMV&!|l^tG%iH#osN+L>Of49fMY$QZ-_m3Q@8XhLt{=|7Mnz z3Xf@g^ghwbKV~UOc+b0ZF<|TeUFdAKp0Z2eJMPrFTh>qk0wgQsqX}liW%E17dMa_h zuV&>d)@8`y!@NcK*1o{MhfH&T6CRUA7{%Aq==`XYVquc;zwfvRY?R7A7M^P&3lb0q zEj(Vt@1zPxd6g$Lw*FbdyKwvRS2TIEhJfC*&GF(FemM6}3HeFmnG8sFJ?9-!ChE|z zDD8}`6GQ4oRb#G$m~Om`c?{47kpd5}_5}0fa)KsKhmHPKXZWMukbv)ZWTE|R{Yqq4 z5M^+z0lCbv`?dgA;6iv*jb7HMknN^RnZ5%>ZptHCagAi3K@TzwI%)p)TXEK~VOGr3 zV#FrQ1y$b^CqRtUYLzNyyp{Bj5g~$~7i805cK0c@Ep%d3YVAvm|BYvT>EnwoX)F4b zCwgS?84wL9-9e%)HhY~}W;ZZv6eu%>l(SU3^=_|X?R&73V8r)*ISFIpH8Ig~&3fc- zm(V}tYhhZ@R~-IcLn9oydJu@Y<=vya);O#FOJ>9K3eBUh!1}U;$}#7xm3DKImT__e z6t+7D%9+zyIn_yjk)gVcZ_^~wNgWfv>x}Y(9&N4ZWa@dY#uKr!POK>#yb_RRY)hZz zw?vdk*E`3a14-#4 zs&Zf|ct+$bQ?dVh`YW3i&c&<~@6`&0`RUwKyP$Sw+lSUxia%&F&L1BVXP&A|D8dFn zEKgGFzc|mVtM;`T6b-V9&=Ou8HyimW{2(kM-)@fEWXda1k!(T%-sbjOwkOwK2P|Fw zFMT)GEWkVL-w&n_^zK9L{mUf>2MI|V6FvQ1F*a+8%}>TXvt6%WH3uc7CyTrxGi~%- z-|VW2^1C=KUZzWAUXwy%Z?$#wc`eptU4CNydeJLQCHe&T!5@^I4KB#*Z6}0I7zgdd z6~~S18E2vhAnv`=Topt!$Losm?a)4QU+aYw{OJ}aWq1f&8iuGGVE=Ny%Q+XZetH(l zJ%AM7)5Jg1oXNYKtE`>sk||@0K7U-_l4XAYxp=-3X`>^0QWD&`T>FiZ-IiRzI*ykG zdAzEqp!`FdIJdVA=*wCFR-_an6h_Q1T&QX;StiX|S;DC%_2Gh22@WjPmH; zMVyIxH_-)#ZV_6IqW7x!m%BD+-zelY1a+;9huvc{h_DDF--p^39}d`Ad#PZ#vVri2{P_7Wj+6yE<_`uQRp*ey(!#nAQ3s?n^$O-9#@n zDyV=@%E(!qoDm1qytG~5n%`43Nwj+Rf)NZUeoe(MVyo#cIbAn(DHI6%_b7T&Ab5cZ zz|@6&wUDtKDL9-shB*u{3kmVk?vU1G;SNeglt z1FV7rW%77sD+h2JliT9;D&Pt|hx(HT>y@)n{D=qA;lr<|eowQJ9m*&_+hWhYh9r>I z$+#C6*7Pk)R^Eh$_gH`7KdA-wpLfYr`5Ot?w9jJNVm((gv6=h)tF<4vi*<+rcy1p| z^?moTu1D3V%Bvo_5;MJO7y6C|SavfWKH#T)XjcaZ2cjP;&j`5jdXSdRSudYoI`$4+ zqSb926S2$=-Tw=Wl=yOGSl8h~NT>n|lC&6r6Id+wUQ_l_J1{={@HfA|s+SWox$Gt; zByf@|(>C8eQA>)N8y|gmll@X42^}Mmb>pjd5wG}BohR%yfbn~;nYN~;|IE{jGb;|h zDNumSiz9@e(Zz`}CamEI0ihs(VB#`9Z|MDVR(N`dRxZi!0jM)DJegh_uPtm`C#2kbaf6Yy{L?pqLp&f8X(=bjv5hb;5sQ?UI8;M~DpYGlhy#~zd~v(Qz@L!hX2$^@x5T=@+5*fTtr;wer$ zs8owovOy187`J5#yoE=XxioFHlv#LbEgTPws40-A`yN_sPuO+sj2i5a5-a@ZdD z(xbznc}?wfPUMa!-|^i3emB%%TxkwEBh9P4zelU`1o*_crtbh*s=DTq`h4O54M&fM zAzlf9_qxWg*9=OKDvfqDE)St2)`Mi%!nFz`IIBMEJvWE&d5{?$Qdzi&{+Ue35zrCR zP9aqPbcA%!}YYs0rPb zS|C~p(h>+watZ>A0zKnczjhV|?wFi%z~9<-dxi@o(UMqLyC&3mog(?2wZfTk59?j25iu0B@&<@j7s>$od)xvV{T z5jX_g;QzZU(!X4TjCxc=TgB0f|AxdYP}JnPg6dK5>)`ojq{KzwINmy5;d_&id?vGC zsygR(>7!7Y7Fh!sYj#6J^fPQN6D&cj%eB-y-{m@Lc(jjUhFP;f7wm6s{L3~+A<;6! zHNAe71S-lH;@8^O%tOKB+iATOJRHK)Xz=JF9I4%LTlCx2(@o%>pvM32uvo^f zNyq~mfEArZfZYb=g6d+(v{)q?j(Ay0_|UhR{3awvw`xr5pHEGW-+UbPp0-Ju4T-~e zhl|5B(v;#CxETt1=e~5xuH;vI!@0f{;*qaNOA=7lf~a))k*qb=LX)IBXIQpjb+~s@ zU3}9HtRoYZEM^MEF+X_AtF4pa6VUD#?!unkUniwoLohNr_y8*)>o+?7K$}qd5>{iz z!2dG`if=`f3#PtUSDmP^e9W1sQ*0U&hw}e%$qQCYQVK`DyH?AlFd8lPK$YJAj>O0- zt$|S-vI8#v3*^?+l!=}6=E<-A7`QFraQw!`P|CBD@|5G(=E!9()cb=4?B7ERqgFTO z)i+gku4Vg_0d48=iX;@jCTo^=#`5vD{;}$6SoTlS=xoL6V+{&k&S>%%gM(5j{o7&f zJ_b6pHGrxeV{Pahs+Lz=Yb(gj`=e_UEF~KvJn@Ed#Ipm37Z#(#?{SOI?QP#mYT?Zl za`q-lu|oEjTUp*p@zRN=L_H(JS$v%d?T>wXs(2Ql(WUYS?9ocbeg_rHwI_3JI({rP+!`UP&8xPFqswGT9hR8Pmmv2%>9vW~JUD^Wz~^5Y^;Cr$?K1Ppp)03? zF{Ga}xb*W3+D(e*2zpovkqcQ+LdF0g`b0ac(GeQ|P(_2k_;rsy!MCpgSOX%T(^m~( z>I5_`E>}K#{&AWV)wJZJyD?BOt1Kl|(5?(QFAB(v5#)6}!SWY54|O0kthGyryRqLpQA=e2Wp$FgG0frkw9?x>UypGcN<1n47a%SbOmygQXf@G-lcW%miZ zh`}dB$d4423GHg9Y4)<2hfMDa-3Uwz{hI9`GXdq~5k}C9kqD5ZQ?U7a(DBOqpI^j6 zXs-3a-ZCwHhDdRtVM4;Nl2gIC?C9Kq5Fa24;D z|0+(fFOtvyLva>7)j}t0|7y|J;e~!X2R_$;`M{gPybGS*vEdd_9kh>i)e0X3U720dKLP&=b^fBfxY(%@h7tJC1CA`3vv*=UvAaVz`kOs(iv%yQS{ zS>%V=v~(rDp{=>zvl!6N3rywQQs-jL*%fxnI^7@f7CK<@XXw(n<{$qK#BrjMB4YleF||eoL+W(Z?vs_&n~;+CT2lI^9Ju98}Ae^!JFf^N}jxXPyv?Nu`+bcMbVzbSB z)B=R{LKJ#x*sS{EhyF2-lXaGV81%9nn9;&)8=43^)qH<7TolT@RgPZ86ZwIE>ruIj zDL@!h!jZwF4JX^Od5t|_Pw%VC6&-5d0Nj*i`>Eo2nf!%!RJK+qn)MS_zSIg`aEi#aL{ zqiS(S8lrcGjosuX*Gxy>x8YIkVets!wq_@{vENBGsYN$BdkuT5?KlNmosxX1en04A zgU#n9OF`&2rTK%8{1a?P2AVikcF0-#L;rm41^mk+Ph|A=-No z^a)OcEl4Rz1Ijdmv|T02p`fstF>Q&kMre%SI$n6mpdV<(dJS*B6xs(>O{3BqNmplR z(jrGMz);2&I%X&xH=|EBc0-zl5T#_ltPCHQ`(T34)-B-!WtW5g2iX{&~`Vs8R+;nfQE-hf_fQN1gRcQXG@Nnl_TKnG@OgMD_f3hPJ#4MRj zM`14EHR^3kFu;6dyd?m)Y=Cz%ULTg&9QDD2XR625oPqALkM5mK(DO0){25&(OO)ShYx=W6C)RSPTe$qa{5X?x?- z#K)|~1PZN`S5s*ob{RQr-D#-W5i8XrHH=yVUfAg52c$(oD%gYG^bIGn?enk-b0bF_ z8!sH*__6ae`-2%1+bM5byyx>E2I`_t9vaR}`_fQL)JnfuKwdGL3h>-lZY4J>#`5D& z8tPFc6?WuBdtQCB60@*2k{=G5`Ci*NDKdnI)5T1i_U7@Jmd#4XQkZtt7Va(A7iL}R$sou_4xv{ z4GuNMCUP}WZpR-#I)C!285UA^3ES#=Lun?1#GB!$19;0$Ke4e^C*$(xM5Eqv*Hpn} zJaE{hKZyD# zB({sTttRj^ZgMZAe&7ir1&3AB-u*^ov1;!G(Jr$ENDW4D!2IUG>}23aJSF`Yg5k*A zcBcVf^Y-QSsH-N~jts1nz?%eN#w~h0HOd)vf;V2SzS&=Gc;s2@ISC3p93Gn;fXrB{ znW%KWNvzW5b(`;2?hno)Cw$oTZ0j{UTa4Mj{-j#RDQq9G7M1kJ~5u` z0Hp(-bQW$(UmqM`FO13LC`M>4SgUBGD7DAV7TyxQ4bV@ZHfrzas)>dUaPx_)*SPs( zFFU6beD%jOXfGZ<<=(gs$oh&DwDJ^8+*=xqk6d4xC^<4tZ?P5I4p+1|XCzd6;AuM+ zmqwae<>I|3UBd()4YR%Z@-jn=3y{y*yWUK&=q{3sFiRKA7S&-sTvHxekTAoYp6;z)NY#*mxlZQTWU zoPe|O^&>W60oKOkaYB7%+Wp2D0bbO7hcvn`#d2cLGrUH2F8ZJw_S@{xa*z8cpi}k> zzK6v?Gq`iLl`2Y3aMHxD_ud-acO1$2S>z%4Dq6CSm4YIAKo+qAGx$}<(PAw8_*dhl z)<>k7;n%Pa?E9pMDf`eCn>q8>HY>C>(0_pF^s(jSYaM$3 zKBC+g&m<}~W#!2(o+QCli_pOJBvCL*^kMF@RHk^NdMs6f;QvAikp`eWPnmihm6?x29`_>#HtgB^@-TDalKF z6iBF6?%1qdlNh1fTO|4~W!`(1JTc>T_~2;S*JwxfZtAHZ)mjUbEvt6%(gMATc780x z&zVZUxl^uWzsga}r8W#H(O%Y6%Qz3HxPT>=?r0UrikK!3@J_{i4`WorwM%fQA0PcF zyHfK(y(%$Q&Y7p2%}T*MD;uJn>0-jlBx_`!5?vA@uv+vEn!TwgJLQjA5qt259^CrE zo;z&Q!cyX+N>p?0^G08V%^CKVV)Jzm$#rqRgp}O>AuLxa(iV5ujUehsfu@&}w2)w| zA&O^UW`6@!IRx70tlyOiO1odIVB;PjWy#pmy{}?ru?0-A5o?b3YSR_bAOI6rgd`4t z_7>dB*T<)DG~~s_%#l8c;IZ=#`>TEWuRigbfg+ay05Cx0H^m)BSg2s)-34W1wvcR@ zA)G*2PY~=vh%Juk%DXi%`uTHYNEux7$cVbLfARTa1@p1dWF`F_@09ib)5J{TlM79V1$NY^sN4*^2)IS+~);&{Ko{r z&<5iC1v^OD)4TiVS^gyKY1rDcyuK6=19RIY5eq^}cqU)NT$`j0rRO!i4*YX|tQn+B zbM!3@A-^Unxb7(0Chw9PE~@W&XZC=%hJHJf=e+wYavCkT4)Gz$w8b<%fJ2^Lj0{Tw z9+#+|Dt`D}kL-I@6_l&--=rMq)+XD>kmuH)&r_eeE`v;gy30^Iz#+vLV;udGk~3geGU>n3F>lf|P=j9? zu&hz2eS>l87HS5L+(Xmy;dNa;z6(gJz6+ociJ#v^E>iD(V&+|(P>u1k&VI)ojPHIG zuL^$pvH19PG*spH3K(@p+_B$xy+il6)1%iRxyJyvU3S!f zMzYL6l@w2DOtj`pEFF-aaOizRddM4$rjtp%z_fPhbsNumfV#@W4jvW5Fy?<)BfA{B z;&$xsm!sj;|770y^y1MRKR8^mU3vEc@m6YHJV&d0<*FAM_a=fUTo9K?hjI2G)^e!} zXVNYnm7;I&8kI^#YK`A44Q=T&^35p}fjRy-;P^B6LFnLmBxIOjSvWm8XEqG72jRP3i&b|>?9bQzp~ z-b8zM{&j;JhQms9S4#)>M0v+~{6t;`_l&uF$+NI*d~%%ZFBdKkwLRq|*{+fcC zR=s^CpQ!LgC~bVO&+}TjPc3vUd3QBtT{tqSE(@x+5gyt9#3@q_$o~zq;#?p*R9-K9 z6XWga(ow!MvK`gNDM>XIUvwBACB^IbSj^o5o^2M3#}>BXEjZ*{Oj&a~eGk=#^UC z;S%~TLnP*9EvCXB*}_UI^{%tiJmP!<+T-;^yZqg+_9qtIEWAb|;5y^o33{&~0E=8K z>L0i$c}z*u^@PY9ChNw==Iq8R?KqoA>p>Qz@zZ%}n>#0mIMy{p6+?dy=9-#M7H!EU ze6z^cK~Vol*D;^(Ts5n*tc*2G5#Wu%Ap`T<2LWW-T!Y&o7nyH`IT!Gscgl@b_1(^X{W?b5djrmw7K`#}+$52i%D%^)X94K#-^&27Bniv-S8Nm>(iA@oyd z#qc*HG{Chx_TjH=q(KQYyfhWQ8e1Ho&weWPA<}hFiKU(Y53|j!5Vx<+`jSXLOi-^; zS{~mcr$4+FRH$fUScA9#G=bkj6Hr7?;d$Y~?((%Y7()XV$CYhYx_ilw&LJwN0;Oe& zwV!&1pRn)r*G+?^uMqu?J(oqUw$+B~a ze!DiTg?&u`5N$(wzU`j2bT`&rPkwwt0N7q|&>G2d_G?qZrT1T;pMz@_{T{eme37ms z8`~^GPEbq&2>(X2SjL4kkbQ;Cs0h41j9-K}TGoeAK{SYL?qKQTp;s3~>!MfIh`?*Y zHM%MZoZyzJXhr?CT|!s!XS$B<<%w>TNA21m`61JqoXSts4gR^1?oJnp&w&m0l9Zk} zLEn7EX3=yyop*tTL4rpO7j_+wZVU7lw}i-|`dR9+x2pRHJ`@#uacnC2bk%{(Ynfi|bi`&p3Ti}HtBXwO&{AIfKAQ)qV@ zNl|IY&XADm6wa1yqbi?%bXa~n?+YnP4h-eB-)e6(9rA3KEknk)x(0W#6$_zH6@_kp zzbD@svZzTOpH#m4WILtBeBq$&xl_We{TQ}HxR)LN39}39JT98gT(SU!c)M? zANg)dUtcvKidfmN^bLDhn-6%OGwx;$dg_$I zMq=(jgW8ADbShW-L9U8TB!8#bF{0+D(t?&^9#B3iwv9IZ;*z42HZ; zUAkeme++hMDtKw})smOKwS}+P*#Zcx`%L_!@-%V)^H+e|HJd&>f@N=~u$6)gEYg=V zRPX|*bdDxgTVI`=fC;+{^PG&!wLW`-xQw)I+^8R)N3@C}fQy4zeHVm|WpoDSOcj@% zxbzeCiO^Gs`D!vD!10UGY_{IsH@j;RP z0|%YqMcg@PLLlgUP2Iyvj9#(NMC>FoSS9_5<}*`^N{A+Y;+6;P!fJqA0c*Eme2XZ- z8=T!+*bSji&Ap0@;SxcTQX9^03rkb9o&50Pk$bi^Yya*ui<{av@G}Vg$YTF<*$T5fh!RnP5@9|gzNP*dYqaSPZZab4h1k0J$4@i1byUMvaeFLJ=Uon_ z5bxWzrA#&m2#=|eyDrc)`{tftr%l2ulkE6t8xp4pjnONfDJ!1Wd2|s#FKiY^W3UbLevvZ&-ZJ#gsNk> ze>e6#h;W4`#5QV@Gvl};8jN@H(I$juh3vQmCA?&awsgqz zeH!xeVB9Nc{8HGNaRh4~t5G1c>R<5#d?}$Q$t4!=X}dG1)F?^(0vR=ps+!R#Ows4n z`NpZH-a$(`c$Knoq$?Ry@DGsma%KEP*RqxV3D#(5p;;p^LRe70AAg~e!_o{;;J*lw z-ob2Wnb3doiu#BrS?ov|+F5;GI2UeH_7L!Tt2E8RykykAlOeIawCv*5P^$w!{NrR+ zcKRYjkRC`|25@j3*U6Np^O{)^`+;?h>u6`g^H}3iW)3#}1A{0TQ)auoOLEb$Fhp*g ziosK*$j*o&NvKLx=S(S0Y0dI=xEb^*iJj@1rDbojbN*Id{oS6E6x+-m`% zbbpLwC~U(dzj2XHgCe#;Wh=L?!0vBeBKoL`?D_h)4dC#(b^Gjh`PCxYRdVUK<)h9! zlDSykcuZPvUcQgZ*%HM>DS=UHmEr;^^ux2ur^BS<#NMVPhituj@JadGl8R!)lI9fp zFEb(Z;rg|!0gk^nHoYI-mtq06+*i3AI@-wRdPGv3uihhG46JL@I>lSBzyf|kuK_Mi zgDJ|Z8gI{?#e+Dv-r(zB_@&n{i4E)9})fc(=X4Xsm+%qDXG!{xBm_2omu z!_HrWY7RZ@R=+n;_tM(nXKLp-)itwpw;wBL<%)7!-hT{pG|Pp#fWHKN1b4mXp%9Pd z#;2c;CqyA|0N5g(AQKew6{W5vStuH5TmVINxJRFjGy12X1=Yh&eN!*AK$b4nmpW^U z)3{T^c*VKv2VlTV8zqdAuon9=9WHf%)cazsl5n_s!#Q&^9Px8jx2`>+W}3Fp>Iypb zO;fzu@Nrpn^?1XXknz}=B^WbwIKgnm^l*S->q{Zs!@rgK=ZxzBzx4oWZFo2qq12Fm zMYY@!kp(EEXLV-LE7sNVRPV5|()*#(j?_m9El&g($SY&HK>IT+bvAgeN_@4kxqWda zbd{&@`k2_lm#_qpT~hZD_+7S4kaEoj%T9#;VXIA2_lETFvEI?^++9RZJx7xyfIKTP zI{s^XIBJ;8kyQ|(e~2T=hC2~QByzI3zX?vb1JsZ z1Dc%J!t`q>dMR_er?~k7!%L62>WVECv&5oH%Ne{(s;yA+m*AV(IuU*@jL(IY>_VAX zT`%txc(q)Lz|BPjzX}y#2PUz(k3WZj(J0mYlKdGOMYsAV-wl;`s~mLMi|cFijPAhd z2|+OM&J*KyC0mw@B5TbMVJ+bDJq3mDflQFK991ewf>Yv6l-7fvcopz2#|W#KSG??# z#ZPJJ#ee!y<0`4lxzc%i6_pTgekGFb*ptn7Dfqg+=ql7gK-O+EItlC zO~Im+N)oRUdved?MPcSoKlX7@b`<&gXOEy9;*99nfi)7n5H#CfX$&%uP3=vuorB`U?B@^mb3)_J>O1}RHRhl=T=&~l#h zX&AFkcMukPd5j0N$N6PH5Qjp%{QJ%5pFe@BF#$Db;xD$?I2=m@P#wz?Si*P%^;?;&s4Qa7)BQifa>cT10N*f-30 z-_PW2LmqIE?dP!eOpF&+x}ziRF9#R5ZDymr$EZHz_$sw9xQ1i`g40nC$6Z{( z4=MEgvsckn8HwV$tRQFeWz&7}{MxpCT&Tfqh5_box~&2)iJU2X-r0c z&AYzq==9q8h#0jvYfq1WT`|9?=?TaLn%@5{w{g#J#l>6nAYU%btw*|M4S*| zhg~%`A-ECGQ=R{NnN6U%^so0k`G8e5Q)KC6IoXVA7RyfC&h1 zNR59_MQ?SwXPoZ25l_@K-Y=HR$#w6jM($*J_bZo;fnw~G3jyRgSZe8s@{7!^L#Nf1 zZ*P!9oQYf&lA_=UV1wjG7wu_B!cOnL+Wcxv-T7Bd^QB4tb80%Wb%ygggmB*s^#*^H zVh2%IYidaxr`JvW|LqZbwGT4ZSsQId@tH@l6sm1dK>R4Bj_g^O`obXKy)e!iLn}|c zzCj~g)vXI(rTD?|ZS4pz?>5yz`g`kQ=?RgPS=Idvf<0E1OucjKMHVFrcIoMI=|8DT z6yAqkU$-PQVC?S91VT4V4mKxuWv>YofXb!qn(0Mp)zU&)2Mxy39Cl{pSRCr;bk^1L z$t+g_ zsY($LafKq4a4KZ0icHe3=8dh}RP+AXudb>S{j-!RnY)+xZqI00IP;SjUCJ%UT5jR!;3`9Uy{s^|hgOa+7_%nQ z6}w1-RGlN!{;QRW@W(*tO!MP&$@V(q-n^e+jD-&U7i(@>i{eUsQ>qP{1AHRvK28D& z#s(-nwP~Fqg3};FV*~&#d_Go|#MC>%Y0$|0r*Xt97^kt+S#JmE5tg2qC}y&(oFi}i zBHjqfz{<~JMN4c~zLmM^q9Xis;9^A0L0C;75-~JI`LG?Ck4YFI`hH}N6)l(2)s{^J zU}S%vDTL;Iak<`SOEIgL|LbM@foA7G7=>$gRu8kNI@V0bw#~g&e$dyU55JC@^6GA=JI)2jo zi)@XT^ALWfNH38K4-8y;clzGs`H;mi`gGba=PS^+c0!K~A{j-q$njY#D0aTaojOP5 zH)|xkx6S@Jo-vI2^DY%lh+pr}e!;-}_p4EngWu80y=tHUP6f#|NX2arBM`mwC6{ zJtgzTQrv^$Po?;l>x%QXkFAymDx@j!p9U8hmntEXOYS~MW-Ej)C0m@_{|iZ_$iCHP z)DqlT)pWIfBKf!Qb0vppO6?yEL!LPHNZg(D*Y+xFpX5P(h|c-f8{Irv2CkHI)QeVO z@aJFbJu@7hkl{pp#>B#w7S+5lD}f*btk`2_Sfhi*Txu4T$p;OV&Tsh2S(f@3B}m-z+p@eiyw;o_F(qnmwZJOZHn|FJrl+|JBK(o zNBt}|1Kp_f&_5WcWz4VN>RRr2)n^R{$Q~rDMyN|4zGz^Uzt(h#b@*zvkg0v7Kg1ZY z*U3i*S7WALB(M{!BAIb)w?=Mum|CFvw?wu@dC}{y!xi_6fNfb zfy%7V_X{N>O4$Au(N@$_zWs{OpcCm9D)|1~x1?3*!$)wG&Ef>eFJrbFgnf_RTA>uq zFy#=v!&);ac&uQotcAmvj{jF{N+41FvcTydzCD93lNaUW#^@?@E{cK|lCL)NuDxva zXmOu{%9E|4! zx&E;%wcyhc$835z&(be!tM#czFM7r~CxT+C;8Q0fhApC4fJ!9tz8Bh<>t3yN)vB&g zEo`)H@-MJkYhzyQStu~aK4PUxG@@-HEeg-#T{9&ObIh<)NyG*_;rD6>nL;7Cn?+q2 z@`JT{HM!YAxsWoiFQi+pw)v-+eqVoNv;Tse@^5rDy)P)NF)-c6B>Z8QVUXMSX@1oj z?WvlG73sOlWk6EucB=z;WyG}hB_YIs9VOQK3zU~}|Ex^n6xrQ}n|VWQW5BU4&sh_kyCU`@ntR@Od^ttg${S_+;QjPW%321e2G#MYj zyC;BR!O%8hM)TnEda&c3(SNHY`SP<pw>11-+3}FGC}JoY6qh=^N}y?YB&*6BCuV_ZyhJ84o-S$Txva!FC!rn+ z3cm5fTiyvg*)l%8Ezy1A^GfY=s)P>>&u~U-b zaudZir34y(lD(Y;LhZ7 zO+5Mx)m}FK2+AUc_>JwB?48i)$c!zX5~U`?W$;a|QI30kn$CFoft>(LIX$Mguy^cfw17R^ZNm0~6*C^^)yK=vhY=`maBnUjH3NUllJ#7-Bxy`7uHD8| zFX1+dP5=i58HYSN+3j$!@0(2eY>ZAUM;^fBukW*T7S1zJGifUBcvJ<*iwh@Jlo`bV|+2Uu-Xoe=RH=Hj`*J zO^%I!`EezOy%?spratSiDj70iMft!coKuEg-`P1GlZ1?dxtSTJS|vuwPBgoGR6JHd zOFY9x$9XelzoK^T=!bY=Z->teEFcOJ-p1&y&Vx-lqpf*w=Z{BBzl;pblS0Txp`XY&(XXU*2!Y+jPViB*K4Dj8vOwS zU?0=A=oaXX{QTKyG&qnJgok8G*ygx;OcXM4xIkyc)eiX9^m>evXlDek0>r;=;krDw zYE(8%!u+yRv(8GQ|HPlZi@a`oKJi_+{WOb}pHlsfBDWnUb8(yq1r)7^uP?`l2xv)M z1r86azrS8KY>f4UN&DpOB6%pc@VZW)Tg!+aX#FAseCUvq8j01!%!kB!Cku)@}?dP%DxWcPkjwy$8h3v zb~u^-gNW~qz}=F^AiO6ix<%q~(W~hYgZ9}^9ANlAa0yBJCmDf-XXFOQdeq{LCylc_ zgVu>K$-SB<)~p-|!az5>X6?yrw(D%3gt@1;0g+gZHa5LoAqA@_x%tJPa{BuLpxXZL zj(!=>kT&M;BxJor35kB*Fe5V4#`rC<$cXIWh;{_RzhtQNi0R3O7k(M&3|POQ6s7W1 zxfs|HI9-E%vhMz{w%d2NizRgY*xt8Xa>YMez!@nym)veD8z5?Oc7Sx=^LNb;?U`d? z9z+D)G`)WGy0p6&abvwYL-cBEE>CP8G&bEBQY55_^A@gt5~b=afjx*4Rso5ryji}i zh&x@K!Jf&Eg(kp(XKCoEr2%;7Vga*JyD|FdYG`~JRd|p|%jb(8kLV$IKo#|rum#yQ zUjL|&%4s@0boDm#Z$T|+s(t<6c=j*2X((3qOAd(%o{{$#S!a%Ub$yyVZS?!qvhqvB~66pW=y8RMlkiUtVsiOaW?N+Ua#G!={$(ZWYQaLh|+GZb440eW)xM%2>(CE8>yu@6E@!-CRM zef-|`R-K2=#CtrK%tmJS6(sl@29pK)ZS^m-m-p4z_vM{2Bg(o@!~y3H{BPix|>>D zNNTX&y&lCaUyXA9C{bq7D(`?}MP`eEp#&UDUo;p@i2_-wvNZN4!c_-rmfl|(w<-8D zcp78-Lmhfo@)q}MAt7Q-7CMnMK3&}LH1>~tH(A(#J@4UG3iR5$7N^)FL|12ok~og^uo1wEr(9*?SbTd66dhyW z%W4lSJ285+iTD_xc6;9uu9I3hTP+Vk{ddsryzO?YX*rsY9 zq37DgBB3_IirIvY{6ryRv*{h~94E5jY;BJdzwNosYtHXtL}|j`X1jZhB|0030Of=f z^R7WAhHkA~h zz2_c}p3@NjJ`IoC${3RO+!s?^nx))H+pG7U_lVL|bpC1F^DCAHBt759Z zjg}axipAHcgG~cZBcR(2=?Rq_lG4AmJbABC=};bA7HtzyD&bK#LF)P4{rA^`F+HCW z4Dxot$BkESj1{9WSoc1;Q)b=DhV0=)Xc*{|ye!|h4xLwR9}XD=cg{;&Hh(YJX+Lfs zpFitz(IcP%`4o0KgDx_gHc?S;j|=}^@T?!KW#?*}e_96NHHVt}8a=58qmJ?hUtW#( zuX%{T$%lhsf1N1Bcf2RW+MFeU2shbZ7rz}xbLjtT55){0gXcfi${{%_C^mt%ZMjTf zXj;-ib)DT-9#L3aS9~<3D1WgPtyCJTbk)v*CU(0$y}?4d%Zz8UqFX(^9aKQmUuT@O zxI9J4S-oR1Ija@wN5$Up&!+1oKum2>O*ac84E)Vey3`w4k@p;2PIELY8_IhDRE7{3 zz)qB;9SYLiWF=BL2Tg2y2Z&M8nRqmXZsaVMvJ z>kzS(i*;8(r{9DU1TFD)4p|y}6;wi_{3k%*1@h?5>WtYpF(6407pOCdgl*Edx?6mS zRm1#=_iI>Af-CL+5OvmJO}=l~r&GFAx>ZuT837MsFY`N(jiw%Q7;hw?x^^i^Vp2hZdd{f*R)- zoU_O4q?qbJ;G0N*Df+vY&M?4@Q<9udz=M`HnV{PH-$z!%)2HbFC`uV6KA1Ra(Sy7U z@3DW2870bj4GZFUC?%`s@4?b;cYlNFLB~eeOuX>f2 zd^lXQ{f;UpftU{z;)+M@;Y1vSbyTiZ@I3u0)))+j>XBM+qT z_z@zJN4{*WiN`K*mOy0sw>5h)qH572I2>2@nEc~1_t90y0%y$wD(lSs!uLmFYKir` z{B;m0t|rA7yB$80PDBL299InEhx@ohY#n{!ZS&~wflDoq!{4s$WmLmCUi6%-5&JRD zsTG`^|MAEJ@?jlxA*NL!g_XZg*n<~GgE9lBTC=CToaxpW{P353Y6|6;GH;8<5;*A- zs1wKYW(C*Ae4_O?W$akkT%f9PXV(m8&?u$cO2e?RMh=cHl)#bwP@ny(L)4dOk9`Oo z>Oscd^Pb!8!8fwoW{d@=Wao2788!2H(5k!X6e})cEVhAdCr!n7NHw}M_HvAD2-6yBgPU-N9idiQf1jo3zmt^%W(m_jr+k0e8FtPE#D-=lf(Z?iXKgW19EKyx z{Vg_&)>g?}W{7<2YfLgc?Q?D?W(Twk-)<8#eIi1;*g@34!L#l8YlV-ttDiO!SOS?ECX%3Yx>9^rGE?Oo>ALT+joq{mJq%d}Z{B~Xks66@`kpiSD!CFPy_9l+ z9(kLkqRPF7;xVAOP#Zq~vTHZu@>9EIW~mIvf5EV;if8ERC7M zjN7i}SY<3mhTCtq_ASDdW%0G0eSB+;NN$eChQGrc5Eb!DDT7kge*M}SS|vtpr9X8T zJ>vUJ20}y;W!HY5kndyTPb(BD+@9PMwQg$&az>1&HXzn{BK8%+>YpSzS^>Gl=}5c;TkhSs=e7ncY^v)w*C z9f8ZaZqE7{r8diMPtqp*E`M33QKDe$p&_qejfJ>=-a)T_jzPjSQuuV33nz_!qy*Ez3it+iijO%(|)w{KmE}xF!D|y+uUJ z-JkCCN@DiA+}0T8=oih&u%X|ke+1TVeRI~R)^vX_OY#32IyMa!DA@kb zC_*~mRYd+Hl;WRI6FGY;E4AIwHLQ2(P%wls>(=(wDgxuBu$lv^-HiI_FLJ9P?sre_ z0RO7XUQxOYAW%3bqKd!9Y&b$o@|x7QQ~0x(>=7`LOh9xRDf{=Y*f` z%Io8(pd-4O&>T*|h>xB9WK%3KTVf$HOr5%GzBWyDbQ7K3I8AToXBY(Tt<59ce4Be7 z=_P@^8d@AW>10VYT=|F=lc#u=Ms-1g3_qavAykU7BBd0(3Do&y0HS*%J@md+Lc9=4 zj5Wnu$}&>)q*CXHuh<+Z(N zGEH8l1uhV|$?UQaDYS~D{G?3gCsCHhjdN|_!{4vUW_=AIoUGVZ&cdKU&%@by_kB?!Jz%2T5b#7l)$+dYl2fjBhMAvh%Cg81meYKx? z3-=VnI(Ow<-Sd?(UnvFYI1=lq=4tQL;4XP6)z!E^uO>cmsA1csL%_3a!KJ#MA{Y%l zFqqY_9{4|vpXbee>0uWwo^dcy`ymxVjZk|d+99kY?ejR82DMW1tmeo5Z#n8V6x*d7 zy5n4#gCjDBv+cHyeRY<~UM3%ENsb4obg+Kqmt*#^wW7X~$JYGjkxI?FejU5^CLlQ| z6u1^*%HLew`9xXZ8ko(nup5rSJkp3ZrL8VQt&Dep8AJ=0l$nccpm}O`)sMy{pUjDj z_oBR^<2)Z^0L0~AFZVOCx){@s#T%ctDyfA6`h)uhmup3=0(_VgD!~D<67)66?J?z` zwpS+-H-o>v^qvw}ggJ6>#3m(xOEbpXPtKNS_ukvfl}2q2*^F$Tmpk{>Sk70fVO3Sm zB!&EG_i;Jw3M3n`1u*JkQJN6DFeFGMzBy?m&l zNnT7cUlKDbmJiQO{Qt}FO-KZQ5|Yap^=?vU2yG(4<(U=|FzSexsPKkAD@Lu0#q@~` zXt}XIHp*_vo<54i>u(~GaQAAr6n@!r41D$2q8$X{je0sc^b2&avuwgNXw6%|rPfvG z{O{1UPXXTKJ3|zR&~JEs(|r*J$yxF^5mrwcqK<&l`H>!&<>WQD+Ol13>-s|MV`hKT z6^&6*BDYm!m*={GqnzRhFSbe4HD^)G^R=9d(k(#V<3%l^i}3M<6UUy8o?K>m`WnuY z(5Ua_lGS0ehoaZ>w;%b+5>|gzh6@QzL6sbq8ZeFLpK{=hovcMZki#3HMWh02D1Yz_ zt0kUybl?Y%qPh-^1J%4Hxz4wLIoIGS%0=O~!k~+gZ}F{G1dZPvXcG2jp0tGNgdtO= z@o{FFiGdxEAW@90f`M@A0(Z#reA4i7Wu1QRzj$Q&enoS* z2bTOenPg&F89L<2%SCnW_l4RWLD{j zoGBsv@>^~(r_#>(nX!QyyXrO?;mP|=r?t*!n*FdXqhC{v^}hmIk9AE`C4!C=zw5G_ z61WRY7`z5j>?2d=6(r zs@V*Q{jq1g)+^7<@ZX}vt=GM%jo)$N~wtyH63x41v>H5{srw9X0iE)A{K z>kNN`@WY@FJUqwVDI^<@Vi+}z4njxDW{BP`IFb!7*TZ`M&ngvfmNzN=Qf9Q@6 zHKDX8#VjwaC;23cN_>wF4vXOYDfzvXBjQDu+D)Tegb8IQwNK_w1c-X==D^aLxW(;X zlJ8!kD%|uRf|~}>CF)XgDN)%5J5+S(lmBEQQyG;q7E#Qnrq%P-lIMFyo6BEs3|Kq9 zFhyDaRh@EQf9#O`nz$jrcAA{%vH;iox&!L&2xW4cO`K=z+D%E@=#$bu5B^aLmpuFt zOTVywB5R(vsMZ){s#!y=-RjUe2;M*UZlwJ{4s&mQY+0rSiH#szlp{j%Dl1ao*X zDT_p7Jd31#D90&Po(s#I1uwwdZEfy;?IBO=k}jv2G3CkR`HO=G_azS*pxsW}<9k=U zjius_1fvKb)6HZT1r;jdcxlRG>*1vl%g*OM+nhMp9U!VRvn>0hB6uX6sg>Cbc1Y<- z`n0E^U))c&%|lU$jmXRlE;T2w_sj!OeaDPC=pUU|PKvgEZ==X#C25)t`P~nuAu(WB zQ?&03od^e8D%z@qtFo#lUGdT*&RJB}5a@eHz74UHT^Jc0NuJgDfZ3Nhi;*AA*#AYK zp7UJ?y3wCfD-<(S??PU4V}2ZuiDxwXn8%H>Kkw*6TB2QaqFOhA(3it zQI)^vdUr%lhN5Jy+am6-yM&m2JwW)uj6_Ng%c?igg}oaLRP7HJ;>@D88%t^3sZmb@ z(uBVTofn6AWFITSuJ;n|mt<^WJG%`(*7H4^et{$A^hr=Xo)vCz(WTbew0km|1Yr{| z=DI8o%aeN%I<)!@y9)BVig~*`JG;^$YX}U%XQ3%>su|8%_HwbW^_z%tquZ{X+0WMX zFJ9QsoFHGddv$*H?Rx-ukmYmG!B5*Es8$45Dthf}sMt3HiuWvJXNJE}lAtmgD!SJFdVT9-#+Cq4NaTE!hOJQ~P?+ zqe4p7y1PT(9WXhpbCV?@24@<453Eo>1=&oV6?fxGZCP?k$#7lDcn4yk+Qz3g(R)li zBCh>l-2oI`kTYw5v)C*zM$IO16K^_wGHp<{t?kxiC-LdjOc19OvpOr@>RfG23entL zRz34pvta4Zul#gZVo*EzDM9DaT>#0a-%W4*nnSR#v9L7Ml#L1?d|#YJyZ4thvD-@x zvmW#WCE7IbnN(j;Whre9VcBTpU{Ec=dK&n_=I?xbh3FcX{BYjPrB z)|W2Y9=yO;nIb5}sA0s)C`_emA{CPZUrVa;l6Va`QMmYAwpXV~J|7cm{*aD7?5fw2 zGT|f2z!DsgQmaffC5}V%wct#r<>6Be?M5$*lQ*Z^c zPle1on35q?iYCNc>l{D!Em-Bf92K0ltQ$jDI)ptLs%&Kfj=+}k;ds?|FgwSQxHsoH zZ>R$%ZpU;6O^H{5aV8)S+7G{?d#|v?09Kd56Qkx03d>49j9v|uCalWm6N_d-cdYMN z{HlHkFjlIfJhN&Q3PXG@`@GYT-E!eQo{kqUu z7cRvK8vcL|J^fzoj^7=#O>A58bi! zKjPe-UQ2=*gJ^K5S+;@UumGL(Txo$`D!q%bl_Z?bZ7dta` zLHCSuTfcbHwjCxJ(tRt4u-UEsQ;1dxhezt=&t#*h{nIt%`#n&d!ovGqlRERUtr(`_ z8;38nL`3#;e_KZP~{&Yez3T1I7Cz`dq6$%b)1l8 z@nzMU6UY5wgWq^SI;9Q4nJ_r5Q=AF~iY)#DxhByvfD@r*RS1aYXA@#OBMF5v%o_M3Ij zh8sXtx%Ne(DOoG}!}v`A_d|o0wVB6i+Dq+fu!&|o1^=V)M(Nx|Tz_#acdB%)@*D3g%EURt=E+RI3De-(MFnbKI za++U`WmI3fE4PnxqTY{qM21zd*TA$vle3=`4O`0e&uc`Ely9SLZ}6KTkR2fK+3>^Jo0C|@;n#|{Z}Wl?&lT=ZlgNt_`i#}0liU?TT!H}UzrGc?c{1encSLl6`(IuTcZM zHTKrf)--5;M)3kq2yDKbI9}wzFxN?tG}E6B&odk|w?@BQ3$gKdPjt$SGY+Qg&K$K| zfzL<#{FIQ2TjBf~6iO~w`0~DedW4lUgV>aS+5OlzYJGNk(B?|!r885MVbA^0nomK` zBPHGLGJ$tf>U?E{AKGyPv9DrZvWCLFVlx@|@50ZEXM6naSH7RV0(ve#OkaJxT`qZg zR$Vv@MQ_b8sF5EFckQrIu1C)owMy>JVH^_~Sz#>S3BuyBs>z&q@@TOJu-xlcwaI%^ ze)oNUe=9FKC*y&!v}ZL7%`ZY>fgvk3F8;PvO=+fFSykYLk43M-UtvgRRu`6;NGoE4 zw?t+#Rh5sHSY}$?SvAcyUI&$VK6lvzRVuN4FdKT0u36IWI&o+ZUl$*}=lU*V1W?uI~K*gJj4JUH3k91D5u0P1#4cgeQ zNyvZ@truEn#VJVij8c#Z-QK!urVXc#JM>vOUdk6j0x{cp&Rphl-G)b>Qp9#wzirMl z_cRu|aG&KqACV+qohP^zh>uNog&pH9`^rC-oXSXg!>3x2fWmk6V7uI|;?R5T3#|HT z1W4CfnpSR*Y&dkxQDu}rTZ@vbep8(ym#cxjB($E{Wc>W)YjNas1?`}O&~EdTEwk?k z)-bxLdGXBBVm@>iVkbhS?ZGQGC@h{|s;;5%Sc9&uRBk@EJJ_=8+<>*0%vHzfrea|8 zU*?pnIrJBwzrcyBZ`!K@X@NAHzw$<}Dv4#QRcdH__@2C%YzgzZU-$@5`SSID;-yaV z(iI{(Zg-gjtBj9zmI(fXj;hv04FZGnWcHTX~RiJB|80}AtR2oSWl|Ty=XcYMP;o*Ibxh(%79o{_r&g^ zqI&z=w8sO5vQ$o%HT*qj$qRCeZBw@TyL?1-MT`Y)IYo5ca=|76JA!K&Gdhrt#1#U< zWp3<2=82#VrecS%8~S&~%?|!UE}^+H?QTKGi({fLm+k81R+98*EVvI-3ym?oXlzDO zK-kI8u<*~I!_J=ELdu7_uss%1q*+tBcfBG!^+ z&vRA93)S-ti)#9ZZ5Yz)Z1&;S)>$NL{4hXT7lxYR?!u&4Jz3_7BxNq_n~+Tg4*9=3 zcCp)0NYKukJv{CsvXid$Rn+Se1b(QYbW?>b-&Pl^Knf<+3fLtpSPLxULP*ScL7Nhh zK6(XOsC*jG)Z}dS(sKjl+q^+)>CvqAJZO_qyEQy?m@S+*VN&*= zSpowB`B|v)h*b$;d+@_qU`$JL^$b|qYNh0`HMlIGVvKrHOd{_Q=J&~4$2$u&Q>5`H zrrpUOS6%^7btE(gC8PTAfvT2e4v-Ty^hpP&2j!%+sBmlr+IDOSB)4hB0mS@*OW4O< z5Di!JtY~80Q()O5edKK5>d$_njfc{DovYw_=T4elRv6zc(DT1~lHhDHCtXj3h9pI- z^bM|`c3-DfGvajhZCZrP7oz;@7iO*+Ym%<-5%L3ooL$Kv&lMfnk+C5F53QFa9i~Oh zvF7Px$1j5`9Dw1_Afwplw?A*E*D7FhfO!3UlTs-UI*~darBuSE!PJ;3K3cqf`yKw& zFTvfm#c54OgW7G@FMMum(@wu(9xtpQvDB!&Do^jJHBAPb%X#a)NHL03SFUlN zD9|aTJ~^N_;JVThZQ`{ezM12mmaO)3tdXx8xX=Bxla=K$R!^Ik8`&;NC&fBb%B4BJ zmx9Q)8gsFc{+={KJ$+nmBHxPt9se(`b-9RoAE@>km^%FS(`yuu=$+ao8&$M zBU8)bERgs#txpk18>VA*dU|=ax7_2j@?IWGmmefW0ur(>|Ft=D2&GekDt# zoWo{Ugj>Sdh~sUZsKqk#xl5BSxIuB<^Zb_Ho+UR~rIua$pY_&`f*7+&0iWX-j}<-*??8HGV_+m`?+?05oWv>!7<7hFM&GegNw9QbpE01Z`rVm zI@R!&%-Qe!^3;=v;5&=F!!xtQlea9bY1WWiWc3p3@1wQ9`yw$xOs$w5L7Z*<#>zXS zAk~Rmf<9LGQsTAcfWOLsc~Kwo9FOv{`Is6snU=lt+0H!tpft>c9fZV*9L^iVu453d zJ?_m;2s$sPqTj3-N#b>ky@9bj`NmfP7YaOMas|*44+D@Q@tX zA?@f9`kCl#TKNcPruv6_{}j6IaB1fo3JWOLt`;~j-(1hEeLVM&Uw?lV2D9dX*56cj z0R(QQ~K5lDZ7*Q>RCGmkVhh@0Q~KZ`4vQUYwJT()a>4(=aY0HcMQr z22HY$(|Aojo>UpZP_O^Z_yG}UyDm~_B$dzyL5mYpDe!m{Z;5F;fUcM~$-Ub&Uf5BH zd97lwX-MKXh(UF77Z)wxHj1p26gK zpQ}+yhJb$c4jywEfVtXQdv7D3L!uc(YIe&$n}$si5JYn<>+yJh*XT$OZCR-(hqV$aef(%Hh;1Ok z`m;2yL*CeYNWcJ~Y>wIPgBu*Zm$i2$HNR{oH%~G3zZS1Z-CUI59t67TIEZ>;pikfY z@;##rOoh{%Ab;)CbnbF|==mkpUQf!Xr3bNg#^)ukclVJX375odihq6_-}ar3$|Q3S zdJMiC@mI2vJ5g(Jz+%zrVVso~8=S3CPG|_e^#ov&fZCsBf1LT$6GQ`?M&l2its(F5Y zt4QDHXRYp7UlF?POz^Av Xv)C0GD0}rFTOiA!ln)NDdWvgrf~hbXVb$6XIEph< z=jo|4{c@5a!&b~Mui~@e|1n3<)LJIlucF9> zJ3afnsFMdgm^*B2Ublp(?|F}h#mhWiQLfBz92!H_YCU^MB!XvC7I-ZW`l;9Od5Th% z2EJ0O156`+_V}e@#hD5`sGDMespHjR{l7Q{0^5eLj@=>Y112!pDCzsB?0X-j4*xy3 zx|HTPz$;U;D>+u{x>;9&3od+Ub@S04ZsS(D-5lt4QwBNOTHb^XsR>uLkB47#W>?== z_6s56^t)O|j=p9JnF`qE127vq@plKN)q?rFOVllYUeJV_o0liq@>;7nk``wAW13Fc zSpni8G+YwL=8HHSl4^t5bnQ))JnU^KF>XFEPEJ>v{%=<6+zIK71;9|tSO*6O-lyw- z;U5n$LHY%Dj6*|1n2+vA89Kw4Mn^{GSJZdaAc!Z}AbRz>+ioiFIjs|dzARg;FC57;7?m0;y6pap4si6jje_7Xcuv?Vt_=o`N-BXZdXGmv}O zV(G46<$?b38qMm_)SQNqTQ{C#dK>^j4HepJHb_Qv{)>$pDBXV%OT-2WncpM`H}|+g z3xj;P38NHs2|?UALPI58OXckFAIaBcB4c?ZDJ7oRj?58-)Ks8~!({sB+rjj-&JC&- zA_Y>Ei0(4HWTw zFIYB+h%DWXw41=Y;Kwi6Gh37?4gWD}G)s4>QB&Xb;S*v{5WiI*>z`>U$lBJVsB{wR z-;h97nBFfaBj{jt7+n|{zBpGBu4M;s8(hvp4jj<>8eTTOFgy(v%e^)ibkcX8*b}Ut zaUV!wvf45``); zeVqXvp6UzC#f+m#R+!~EIKpJpbs~ACLH7k|_P)c2(DD9@p@c~3{8Hh9#D46Jx^pD6Bc@lQu$2mkNuPolh+0MR# zg>{QxziA2iVf!OUYz`&QKBSuUiec2X3fQ~kA#u2+Lp-mctkfvpsPgRdE;~7w^;-lb zWYzQY*dyh?5^H>uj$%jW)7F$yl)rBS$L`^j0qJIK?H!#H%nLh`pFvhfslI;)eb{WM z6|^kzmT;9733JJbtqa?nE(0ElYqb4^v#Rp1Fk(L?awy=Qwb5awx(d!=)bH>v@2Z-a z5AQ^9T+X67;3huE&cSEo%}oZrHH1PZ+Hi;cqtvr z;s8S4klux(Bixujh)GF2-32M+d0*eABO`9o%|D*0fmqUfI=r+j3xy#Q@T_WZLg8MA zW^8QiU7g}ppG%X)-KO6Cd)i!4*MGMk*3P}qs72``DfH1~vM?iD8SOMl%)i|G>~yg$SMZGK$lTPE zFk)e{BzI``QDNUua*JadRhL97zPxjv+y|u0QfQvA3FstbFU%*wTeMaS&l+{LjVZU!+fPMo}XY_oh1 zYN#w(nC;>j*X{(QZ0aZJ8i z7K4C!RBj}0J;-@G5h^?oZ!1^FM1gIO;o^Sib~P+y%3N`vFP9{`C1Y>p)4b%m?>^=j z>Nb4Z*iV=Ss^HTO>uJgIKNsM2?18y7?BV9<6UODdyoXQaE4?8g6}Q=^S%!Ejt08ZkL)>PK zJaNui-l9+vooNec&IyQCqZC_a_jU-G34jFZ^M;^uC}w@V9>>wYSWbtLD(ZzlzxRZ< z8lutv_raxIP}a|9n2M+Gv!80F3Pf{mV#TX6ifMu`H9J`R*pqrUOC!*@1~6XM;$@ac zrB1qvJQNYmG|vn}jDCxy4#gOy3(HNkq-k_&_a!Vm%y1+1M9rc?VB4EWk++_V^7x8ygWnTV5PC8+w3zG)o8+%d*eTMu< z98-Cg9X)2{A#L3sVs{t-9qKyk(5Wi!bx}_xuH6mzX039y!DnaM$wKLLERRDH4AqJX zl8L%K27#dDO`(@-mDB8zc9!W6Q@!?t)#27o>xaX5-_Pl476HKzLCYowQmk6XqC~)) z6_|nvIk>~q5^qzX@mNd6-_k<r(GB}K;@W}6>81u$2Hs6JHVqWNL5?)NVThEc%yyc%8 zD;_rA=Ch?JINd)>7xng}-oc*%|hS0 zR5*PYa71}c^a}ZVxA}aj=Tw}14*btCoZi|A{)IMi=W|%neiX-f4EoB4DYJF_L1OL8 zgnWb*+v>hQ$L^TA?86g3J_}_Cb!_{+S$VSJU`cfAO&&)S=s^yUGlJR(9k{g*TRUFd zP4^o~w2jJLVYnyqQ{S;9HVh?%Ss%rOD3I3(FE`z?%wLBP{jugyUU|0!H)%?%1d3x}%VU35avpvaY*-xJld|19^Y5 z7TkoYK4w|sGRn09V@FoVR}P7zf)c&kywlr^TWefu_{Y?1?;YLYDVLw&37(vkA@;nH znf77f-Gjh%eL>vNcZFkYN{1LX$%^{wh2`4S?6d?NZY72jv{5!opUt8O;rLH63VZ>- zhB;hKfup7GV7n@3T`Kc*xdf)}J$G&H<6h$&O{9ja^B=!NI1g*fUS0rLMluO4vNb-M z%gtr%1#3}?jy)w!R#Vci#nO(R^6!X-?4BASv_w$^o3p32G3J~lh$-4KdT$Mq6dpF0 z2!w22G$}U4uiQkM72L{_#97H1u8k?h;WJ$kzQIZUUQ9z65rLc@Fe>OeTYM3TzF2*hatm)un$eO~(}<@>TrU{~nVitqIFoLm52VW|B~T z_IP;;^5rPDEed)bCkzd^ELp5wR#JG*ctj9g^UP0aXZ3^KmQ>t<(2os1DO-E;aS}uv zNSRV|4kP?jRcl`ZgTe~syi&nz%M2BZC1gbEyX@FB9=<*pXGSv_A0UfpeS>Ps`V=8N z3;z_BwwXLS4H9i^m5MNdIUGsQfQb|f3^4^7)LyA8UTr21YF(DcUQ+2Ee`NDwf?)>-D9btTwll#kwZq3n_#PxcO;UPb`}Qrgg?NAu3|m8gCM z!D;-in={<(S=>i|XMdP3o=*=Vm*}r+lXu>jILtGQld~}GUb32etEcW-wxf64FDwiV zIDGJUX>9yA|Aqz_3BRp|uRE}!9v_G9$R6L`pZ2ltm;x_Nfqg+^a_5gI6mHls)7kk( z_|Z;y;+l702C&6BFDOR0?6)QSb_U)c^AN5lctVJsf2;&LYa{lCxWPM=tPo^4-!kIR zr5+b9(t1latPOYQ86VM%u2)uWji@10c*wdVB8*68p=;Z-xpc>vK(uo@QJe?2{9 zzVmwVmueH;(Cjq}v)xP-VJ4U+sp3k-mW=ApWk3+i{bL2Ct^=H4E^Q(`adIPTkJdyG zvq_ma4u30Y#236qe$cg97?`qC8^VCtO>SUP3Mp6c{vG8WWf?_59sWW70nDjb0*~&U zTRWhl8h2-wk57#27!+0ess+3VWx6T8Jl9zd*iY&axX64~{q-194;<(W!5fKQoS_(7 ztka`baFi5KjD>e*?1!z_F56#H1};8ryvF2dM*y;ZAbnLY*T7`cV@IQ_A_i@qG$A{N zvJX^zAubO7i-R4H4#MTXPbf%$qm@za88(*ZcN;q<#p^(1^2SB09{H-(OZ{S^8N5O{ zf9Xs@6CawuBu}`hQo;I!QaBAGbH0T-mSH9#$KY$xPnDUi#ay{Zh?d{k?UHHI0n@{D z2|`f$?oD9r-Q@fyXMr^?){uc+Y#HR4r*&Mk*8f>wzA^^cR z$_f=ur5>MddJ@rTP9E)?aQA++J{Hb}9Jb?mJG0Lz#h^h29vMQn3TEhxS8 zP4#)?;B1$ZY_ylABG0^(1c8}OVGia|d-~6z`s(O1GNzg0k`*SdouVu(t1-~Ng{2@t z=m*iWL+O{s8)gxov%#zr?cQ9esIBx{OwAE6h&6_wI$~;nu*@wBuO$PgacD$YS)mHg zIfuWby8CiUqu53n;rDDM;Pbiwg9b0^%zokd=Jkb|DTyua1P0`?GimCTO?o<)^UYSC zi#0Ke5IiXH+L^#$5wX)a#hw;TTa-TGMoR8{2A07XR#Xitx&Q9CJUg-0nNED=pb7S( z5f};UnGkX`0SeP_`3D}?@FJ@0tekYg4t_dY9h!$vCB?wnE_w3BP?2<0r0lIAt2TaA zlH0_qoOL6~?cMz@HCSLmI0hErlIF7J>`GGQuyvJ=YZ&q%-&>mfnRCTjD7huXChQ+0 zY`LQDHA2BQ*QoqVd0FnBQl}=>1^*h9w#J761!$aIrj4oH=3Zj|dPQUa?O2b(>fFaO z^Z)$sDHXQ^ZncF8CdmVh+{z_>h8R?}ZEBG@86O1XbQ0I~T*}nzcP`ch<;JK5zBet- zV+;K)i1VH>?o0eCo%`>fGJYTBOb^N&fUR!r996EwR4RM(wmQn!{kbcD>tyV|X9OGfBvojQO6W&X zK`P}O(cy1yE_4DC!KNfCINOW_m0gnKBrD3N`#P?{VBnFmTXu}%W!XLL!|#U^#glW) ziY;^&5H@=(wav+jBr*ltYdJcJo0OQj0ul_k4J2J&8fQ2F9K=d8Q^r zNvsYWN{OFFaM#n}Y{qcW-GJ6l1uGjY#bNNJs2N9{~l$nxS+hu60Enb;a%fHtUQlBkC+ zY99T>FQ*Muu=IqnO*G(uC$eFTN)S`+)txHA2Ht!QTfDvfz_@Y- z?wY9YJrJv#jmdqeM?XX+OnNQA?|09`dLd@gHRb5O{;v4y$djtS2)2n*shs#ZX*r5+I}PMERvDK~37al7O3McXJmu_ztiB((Lq=LRe2TmuBkd{~lOMEy7O@>y^UoOqW7{T?! ztJcfwgOkAohk21Y{%yi6|Jp_9qwvpip9DESMT%u@m($1X)1H-CI8S`$HnZduhtR%x zW@$~*AG^&dV(;{i4EpWT57VWa2er7MFFqu9Eh_4iN=EvHJF3XcvzwY146!#|+c&pI z9Ng=fT5bdDzai0U+RERR?rlPt&yJ*edkR>q)hyh<*=7k}e_nWQ$M@}4;OzacdrWbq z!4c0hErZcboHXg7Uw!pZtH+XOuGx?HF$uP@rsc3^3OG}WglsV>ZuwITwK`$K*oy!6 zFE*wFJX6y3nQpcWbU*}kOe^x1b+(oV-*u&On-nr7l7U6cEIYKhsG8ZquL#CiaYKHx zX$=XSxs<-Nd@%snjFhKvk8kMMJ(o!ZI1d+%%8m=BuHF@YtNdKEDTmyRYZL?hd*i!q zM_)rtf;UXa{LFH*=rgiLd>pDM>U&pwEck;HxX1lmPw%_18OLQBz!yyv@M7XOu0fe< z-qR^-iN9BGb$nlk>{jskf6SB6M?4*#?c4nRX3_dGw(Zx6oz)>Z(xuqlAMU|%>?Jc3 z@n6vZG+*CVeCp~NWJboVQf*3eQphp&MZWQ!jM5m5DOS&NcNWhsS#Zp%L4F+8v4UpC zznt5=v@L&WHVnR7Ga@8yI*@p9+z@cTUV6s^$f+=Wb}}i@Sl<>;n?O!;O=P@7U}4@` zKeqM4&^;AABUnH;q*&Mb9q)sU3g*vy@9_YbKKRvCQLiB75L7jfoFy7RAW=C6TOUc} zdJ!q+W5gp8sy8lK-bJg30rkISU{7mtL;-}YSXH3WU;$Fkieli5FD z0+G|!3(I_mdBjdiCHa48xs#YIY#IPAim*B%2QLaxzB@jp+zDP^mXFTaQ62vt_HMf6 znT~Az6$_>BiE^U~vw2VrUT4I1QU)|?)A*RzXb5m1T870qlgF$QzUAE%O{A025)*2C z&95-&6hj0Mj;M8lqk()klQYdeWM_Gy`JE$qiZ*chcS2_)sZL8FPc+V9q5Tgr7ypkx zP#zS;O@L6S|k+a3yEd87zXDVFEVUx{{GpTf=?Qfe$4j68i zqce?@?ex-$0w9j`u{iVqR3kYz+R7Mm`7e0HKM8>wAV%`H_&rdpkTUY>4I z?|2y@Tqa4G&cwlMH!ecco!xFZAh#4L1Em;+>eaf6UUv+%#L$sOiisM#q;2UnDWR=* zq<6Kns`XLnpXDktQT~@QPE$t{kYZT{I>$)i~Ein%XRq?qlMpppR zY!PXjt;ETs!XNC4bdb9*f|l^Uf8f5fPWck~V`52M`GpR8-y6^*z!tcA(wK!R$WlcvI()ZUl5N2Asffp)cWRa>v@yy*R}lpHA! zxpIgfj5fqZd~nxlxIDemdTP~P>bcG@IucaXX^e%zjxBs@dc}&RL-LCg%NLgZ?;=uj1UpBfBb9 z-FSUHc0@*RK10 z->*C&jr^3W*CT=vYt?e>Lt;)sGCNoAh~{lNnAoXMTU!?QbRJR(3f9Cp(-;Li--(U+ z%$><>c+GB9z+I9eU1{psxS7OqyZp}}H00}HllLV|1?zWGW{lCH_Ca^u#XPUK5^dre z9BWmJKeFv5E-263DfMZyqfP!0KRCWYF?%cNucSoXp*Tiss*5l?A*;L}SD+U=D8)rhC!=e>uD-m7em#Aw@xpSIhw z_bE@zPY=biiJV7@!`f_h_&2K{YXTbC{8VwXq9R zK7rBxP-bP<$v9#_tfKb8bDT?xxg^kAIy9H(v4d?H!$;EX#D!%g5=QJE(fS8xs;Bp4 zcmpwUj;1`lK3UI1s7lty?a8yBA=%B&Ye;cI9qD=t6Pn816X785y$e%L2Kvk)&X5gj zsKW_K%_JSE(-Vp`olKl(LN<;cUu@HDUwCgrDu^a*4Ajz?kw#UQZjzcCZ0}^tPVmAN zsyLoF_uSd(2gLFxe+nSkJzt<&YS5H=L!9c`+%$;{etT|bVOm0z{d>8Ywtu;flnH?E zm-~)2JeC60a;-rQUOxCqr8NGxkfi~Wg<@r&+2JdpR4juUAh7Q;u){ zEs&8{(bZ5~<$s!Tq!~HsyJY1fRmJM+>YDYg@#m(*>;tS_ujnU?dcnS2%r9d{VRT}y zqyimYQ#;>7%gFv+RbK#Ec(u~@_ZCt`B)3bo3eCOZ|9(u6+lFcBA06)(Hp`E4rGNdL z!H#$1Bf#tt;KE02JYn>av+zX2JTOxEjSlHgh@sm40@rWVwtFoJ(FLr;t~dauv8kOW zUU8PCJ((=WoQ)nyY397t6!|hOfVGzA*Fl)R9ITci4r2L>xQbKvavU(5=lNYWl`G4f ztrZWoTbb2GrDjHv88^ltLYKziJrVwl>!=kz^_itx8Xo>@W8ur6jusy3kK&%?5b0NM ziA{uGSZU*W=g#s!8u*mhei$3ZTI`B@_{*1RpSY&sV~UA#x2t5=RXBT+Zhf5(;C6Y_ zVY_7Vt`x-)>3U5XFKZPca6>j7ygBc+?hn@N3jjwKYWU^j278W>+4 z_e|+JN+Y)j6&OIRme(2`F8&`*Y1>&f$%8HF2|Q`wCimKFj@!z@mHirqIG$`HtDk;- zb5vqHi)BG7kyA(}qag3KTCD1I?WIbza)Wajk*(Rcy6#@AcO}k~M|y&8)!H6kV(77x zJjFE}N>F-iWiZq@a{YP{*)$vo6}-b=A|k)OQpDZEOwVfv~f+vdJ4d3j}J`+qd! z3B|Vw&wsb>A7vsCUe6v+H)~JJz1Xc?5&K0l;Beyar>&6~Fwv=F#M@sjw*+UzxWYTA zoj*J5`~EuJ-j<@Q_b$a1=lnB)<8-p})i4Eoq4op1`UxDQB(h4v2)S(-LhWt9Ta)CQ zaI$`Y$e9e(c8^uz4?Mbc;O8;6lJ6}u)aagb{Z3;zEPiL_{Rv?yQMdZhg5C9#JjO00 znQn`_j~E4skcCA|+2_X0&_Zt=$03)GowUBSgZGD#fjk{GGjLF_3BPH@O=?q9+mpAQ zd8y?&xe2J4J#^rN^aS##f3w^RkQR?9IPR^xELH|D5|cL)r;v~YWF9zOjcn2Bg%$wG z?Oq`shrg))k|F(d@CvP0bH0eup*Tom5VI~4oP$0;3>uhAIM_hU>7qnb6ZV?K5yR@W zb58o2`JrW|M&SILn9TD>lcDTC1u}9z`EA$)%Q!CnR=kVv{a}CW5s8C!fIME`&h$gc?|}Cfo@rSU+xE&9 zw(&YtL^pOb4>2!XfLi0KNel*a|C-<6VpL+X+8{F*(C@z1z5VI0n%XkqlYT4Z`oV_Q zkgxTZ--{NHY=fQ~&8YS?6h}T@oY|H%K+pu5F_!+GJkcvH`5ZMGk2?|%_PgcRbEsO6 z1&=R-7S(87Dj$4$n+Niw#?jJqscCv;^K9p4Ss4NuQHrp_I>gnqZ!g?aLol)1yO`w< zxG1v5MdK-miON4(iBNYMXf!UF3DnF)7YDggidSb2zYhU=SEOke_yAH3ZgrHA5mAe? zEu6wW*DkPnqZBQ<#e!1P)QRig+40*$LoUtQu1nrY0ybwqk@4lD7574{{dVwuOXs{j zB6a8c@@7`RGIODjUYOD3a=OHehW(E!HXfYCfNi7k=J+@1lc{V;LtqYjv5fn9IT20k z=>*C=DzDM&fpW&)V2nd@gD&)rKb3NYbCuyP{Y~2!kuW{GZrd@?PN-gbQ|=k44MW?5 zu409ViW)A?iU|0x*%xHpSw)&o&&GmF&h#&p`%JEu$X1*J11Gkj)+c@2^!PFz=|{$| z&(mR=fg_V{=T+ogtnxP5hCC~eM^sF|-W*->a_>!zh_RFlhAA+1x%pWz!#rp|h<~^= zvZQ_6IO3zcwRrK#Hk}ANjPhvG%=ES++D9wrohVL?cKb5Oxj6OeTm6J7&ac2+Jy@p& zmD|8K6dL^BLVKi&$7E@ND|IhjKFR{+H zJ*hlZXNKi=QMREgU`nwT^c*h=%J5H?823&F+4k_4-Zf~n69m%z9`LkS^XHuuc7Oz} z!s}LZ&wg9-Z=W7G*p}W8#mwLp7lWw$_GqY)RelklkR!i-Ev7|5PF?go9J}*KCSiRu zfI&8MAz{=NH>!MY07V;-e&%ISI(p9*?az%QKG>?odF-Bgr6@uGE+oC-^Jaf*RwyTio z3fn6xQ8P9(s;4j9qD$MAy+rYtE_&w?U@C8HN4{M|zj# zSnU{={2cBW^QI|ivYvi0g+x;lrSR#42B)>>bQ-*ZYs~c}%GPtC;Lu*BG32s(5p=z) z_C)5-KXV>)Xq$md1-w5L+xmgoj@*AO>!zOL=NQ+ zhci}m<`~`%pHLD-PKJ>=Nxvw*`QW^F%5`~q{hBV9egX}%UA^xekD72k?tE)WU`cJH zEYS;TY6ITD5w)mK)EUu6{HshUGynzULQ-Jj?+GShu;k+uF?lB;!!b?)E7>k5{f5kb zV;2{wj^jj&zW}L&3h3FNa}6A(xwm!tVx(K0l8c6uX0w{>ZUXS8wVZYz&E*sgJu2U< z5i-zz(;ibj(9pb-WZ_Sb_A@s0p5X|bdLqcuG)QBbGEQe?k3yzE@McmtBSt0>Wiw2z z$fgp&0eFthPjZT@^d;^}D;X!{n`2$vd5uhSwrT(PP)Ci+YxK*lzgabxQIN=Pgbl6e zt1@>-Nsp80NS9_pRqH$|qN@&U>pWbFJt|`RsUKpZQ|(mMSJt9M7%pGnaan z5Ib$}0b=lznA%?)?C)PZ!s`rw`ZWrF=dd^UPT?SN`e6=m+Xdw3pE5>tjw-#Wrd>NRgxI>-4Aa15oA}Jm{npsnCNP-xV7Bp) zQ-e)BBhD-XjdA0(o2X}NM|3(sFy=W06Q3DYDUjD<)TNv~uxD0+DDyeX!sx92<{9%b zBd3~nvp#%I&=666<)P?tx30huF}H_M`nFjzSL8-5#Q*rrOz_z)LyB3gUj~&n6UBv4 z(v+bD6nQL&+P(8raxhfS$!&^6@OwT?6hyigX?K}UEtpCfZB*EWL7gRAs{q4alTD%) zRxcrKn5`kSH!X=e#VxJl6PM;p!)ZPDt}U+kHFsUprpe1KfE0s4G-Ic4k)Q5EunBB$ znpKL4zK;q2kri#xnh_1xhQ)JWnVQ6E*z?i0ubYz*x=;ZNL2u@lVJX>RwY}l;uU#DW zlmvIv7BkRE25SKw8Lr<{y@g~`msp^OC+AST1h-v|##a5C&8B>iVtcLFmXI3MKl?Qn z>PsHu!5cn)#s!Q{L~hec!Bumx6Ge1Y=~4-y{JU_^~t2K0OC4IVw{IPeS0)Z2ZsKQe=C zPFC2mps}=t*%q7@)e| z36G(q5}-YHq&Nef0G5N;zBrJx_uj$}7diezdo}lOrZj5Eh5_ zWPSwv)^oaaJ7UA%;rq_Iu`&3a?)TRg46KSE*CL^>N-7&~=Naj>c}R^Xvc|1TS4VDT z0+g*224>tDTG#8>K4mTpGY&ttd-L>eq7qODoi!KBXfK!U^#SJ@4y;W^J<%9Bn zWgLsNAJts{GE<<&g#6Cr=FFn)dey9kPj6swads=yk#{H9=IUc?Y1YmzKT`I6miGlN z2wBmDg&x38lxMsxZ%NKIezZ4P7gbZz;iI(FL~3ktNOR=R%KjKVdz>2oH(3?TaB4c{ zmGYa=7sT4$qGTZ|86|X(2Cv*@Un1hAI-4ZQi}LNz{i7}fP9~hSc^w!{XzMQp9=ldF zJg%H0a%oX2O4;Zy*qy-L0oOz0iV8!vatq9Uj>;Pi1}$z=Wf$O5HalsknfmhiK*Vx{AFbco!FP6S0&n1 z_cwq0SAfSuWF8ekPU+b6B;Tt)T@S#9%!8gs6vN)HGBbRGf<+Uk`#Dh$%IoqG7Y0Dw zCv`yfm%-xOH*Smh0iI!%f2JvDv^mU^?8;G6XOr;M!-+%OdLw&w+>HF>Zly;Sxyh%r z7)QC5bf7Ah(ojcVWR497ml+QOfHb*W`64J&!L*@<#T}H4v(7`p*~d)@P}z}Q`)t%` z&|AYXXycDzV002JsiO3q9pGQ3)LnkBieT`oQfUij&P?>q6nlSAmZ!Ih*LJX5vb8dx zl7$u=QgHJs^V!*Rt`X|Ozl+XvayS@V#=$gKdef(m@ zBN-z>JPv>F*ZxlQXLovh+Xx!`ir&xtli1Xu!TBU#@!7aY6sFWuwgpQQtr(@4g}spR zYVB7{kn1eYi_)z!Cj^TBq2x`TdCR{H}VcD6jM2Penb#NP=13noV&GwtrRW%=&1KPRtuKNTUf@6mpIC@%$6g&eU* z1thPJxShe4P2j49CN|Jy!~}0hea9}s+Tn5r8#cLSb4!0H(C!%a314jQRIN5P>7E}| zS9g8IsXcr+Svih&i>mVsN|G0L8?^a4wjm}yvOmSf;)2E;`7O)1oTskBxR3+{asA0= zhjGjo4TzBQMt|;JIJ?GR-?(Dz@1#|A9anD|HeNzCCy#^#iNK~ZEsMkNA;Nc0-+UWS z>56_U^!JnLi`!{D(%lUz_7U%4l@GPb^O`1F&`7@v?{F*~DMU+j&}Z-X#6RyIsb#+v zU00+oRppIZVRoWt^~$X6F5KP~QX{x%G*`JvzEa>cJ;i98&f6_b^#ZL&Ry1?H5a6+V zjDxZJLZ(XFX0|ZJ4c%H>M6APzdhm6iZGiQ@B*%-y0T!e;F@q|h)Bwx^YC+kIvP7%% z3!|TA@`YtI#hp6a`(wsH`x-(-^lM8y;c*KFfZXYp-d0WBFMdA5}NZ z&~7(9QL4~Pe>th-Yy(T9>|L;sPgp2 zY>ep(Qj~EYgKmVTFm-uAJ)II~h{~_&f}B+@Tcs0q-OUsl2E@lwO7qqBf;0AlH+l~c zIiG1I`H6XjigYZh1AH9gqdl`jBi14#(#G#g-ZGmaop%m<3-@^Ahs5q{HFy#)N09zy zx!x943w@s1lKlh-?O|pzAh&9M!NYcGmea0GvuIMijCI;hu1LrIrS6C^0k+9$ceJ`q z-?FNCB9nf3Jc5MZJNQ;a#@R`qZujli0Kvcvfm>#;nf#VIHJpm-5`aoPvwL}?W~{3w zpgmc(H*~eC5ga7{CX@W=IE0Eu+!cc*;+HsS6Tj1jYJ=#RH5wfej$KHR9-Ttu3~6ab z9gcCmii3e^_~ozb!DYW9J-AD365Jm1tNZa`eVZ?C4woHk<{|0^CO3osI)ZbGyQ0nx z*jJD|`32=&bXhdOwA;f#qjJ8}fLDW)%Mb8if$8Z6a@6WOU`1!O9$`sE5tkV{c8 zWab&bit-^q2Xz{Eqq`Sazx-ZnjQO-E%IRE3G5B9R%{5Y3PkmWsUwL6?MiP=uEqM44 zx;`xbv8VnWjAi053}m=BC&OqjsY^|Xr)IkN?~1AFn5H~7(bP=1FQpsB_do3bP5zx-gMB^a235<}>Z zn<9`hs+r@etLOFEdcuvm{r(3C(Ipsp{l@?6Vm}=>S%s`-pr67@^3s7RK%t)wupsuh zn0I^MIj8Oy6!S5z<8Tev!3C)AqmPK~8b)X0eiSD7!bP$r{u~-94-v&_-N?{0J|PD? ztxh_Lw!3DRj>vYKCAHhW*6;4=OpHt=F;P(baR zDeJjwLkzd;@C{rrE5|hw5UmMxJlv z3(BHHdv1vChqP{)AB9Tqc|^>E{m3O3J`Z*v%raIAq``Fh;xUye^6I)*+NEL~YRZw* zQf>rvtneScls^dNd}7lkX*mkDn2z)hG~&Jmkac+LP7=nXi05AjQ4-aTD9IG@L5F5s zsoL-~Kg{y;$WK~ei*!}0Wt<*JDS~{jOE|4BR}^~|x=JmK->}7XW+%*2Qp^4qXjP+jm&NT}Cv`4HIou>xrorB-a-qOsc;wAac zAG&E{qK^{Sgg%;e|1EnM3qntngB87swLXdUZg&>QlA!UG0a~jU)Q1%+UBYIcY?`O; zcVV$ca4PkN>7P-@%Nqsn15{x7FUwaCa!vpJURgTu&>0OMQ)T5;gzP2GRD7R3O%>@X zPcHr%gO-)0=BFql&gd6XuJbt@J1e^ssJ<6c-b(t-qy)fARADMPRUo%uD{G*Aa9zUj z>l!!6DnAKY{&@~~ZCNPInF9`3N+nKK+r!#sg%ubYdEi?KY zEz1lY(D$I|cK<@+{BwyAH)WI(E!jyYK3g*^@JmuT#eIF-2l~obv;ei(B>edzJLZ@u z_*a#9gDN~GkORYsHOTb93P5yv_r%@OQ;%UR)@pZDXACA|m8Tx8CuiP_@{%O~-NnFA zr{XDW57KLCi}D`wL{ z?=1T};-iq3#e+|Eb~xi(xCbY9r>A{#*}K)Q&kt{~KtR&JbHunGLSk}2ODxFN&<4wS zzvm9r2U@RX345@WLkG?EtCHcQ-S4xaNvH88>qJ$w@7a_lda+@m75uef=5R=tHi|n= zPK{iY-x{nf;;8`sNNXEG7&6$qb-X&rP~n+o8fqP-ac#Xn3Q<{ElKs{*ANp(g!knO> zM%$4mXqpZyv-r{pqxqBsL?8))(S(n&QKR&HMqT^fkkGCnr6Y4+aQw>@CXy2&Cx+$W zv*f=naR!)##`HR;qf#Z1gahPlQDtOf!9zE9w(K^C^8yVuZOP(=Q-@BV)0J0RHy+PI zU?58VaOJ3?G1AH7P0|xa$!RFwBoLt)4t>6?(ImGcOMu=eR2fVtjFS2R!kK`7i#WFDSW}}QB+W!1-B3WL$ptd)W=1dtB z5dW|nf+ozOBbYS%G;-Y@sr-vAKQ7XC78_irxEKVJfsWM?c_d`UW& zR>z{|5aYg1+)|TcmYn;$bfl3_*R?59DGK1Odk{AwUhi+0Rc{^FDoa1^D67H>7{PZ- zm=z7or8mNQJ9*8Kwe@$go_my2;+v;R;kpV0e&`UdS+JB%zf`6Zo&fClQOwy%b*!WPqghE0`ji zQz9W4>y#OXq@NOgFZ&$zX3nbHq>yhWY1#$O9To-BqE#A{hv%T^eD_#?9!+WOSCM>P z%odLis&Eym(fLWQnvvU9+dw3Wbskk>^ETh8H#B z{$s{NO5T-}vTVZg+`a{KYnF@E#>`{5^4dyvz7raM>YXYaUf?Wz@{EBCuGL&TF=YHN z0K=p<`<_f1EnK4`2)oNEj3CCIEFWL*gxsbe8+UXQnr&JwtTgeHF^xncQ3exbg_SR) zn>R#h_gcpPt6pks)2)|I8v;8Fri*bG4eN0ZqxTA- z5u&OVucbU{>rsi#r$+=A|LnUYLX~5jjjy#i^?@8mY$NbCvd{#d1JY3%sS;w%hGDjN zSV44>GF~k*H22}sdymNH@mZKa?)Fqm3o2Bzxc+>azEr)CD?@q$>JT`w*olMx6x`sh86IG(ABK8}!O6O>yje!? z!`HGYj|w8Z+NhGs>y*$KiQP_x2Nz%HJ^YdSxMI-(k4gPnP z-(?{|7y5Vun%8BP)R9IxzG-7LZ-lE#KZxe40tQ4r$2rRmQ^c{;Wm!9oddhHl^t?%% z@N+rI$rDP_K#y#7#$2oaRcJyT3S#g;E|5CFFSTzdh$ddW(9juyMy7?DNxGowef=6X zT|s$q`>ym=2K<9eZWp^H)9D1^0dIiTT^?ce$bt}WcDc>k(#jc};I+7gs|+Wy z>Llm^_WuOds_432^l&0O%XY#86Gi?ijACQ0^N@Z<+PZnIvh1J$Ex!ZTeIpjLYdv^O5Xyy(yv4q}aJ;!9-&-x3 zX@g;-F=dg=!)mL@=N2QgrUperxvC1HAcq&26mMfL?DifHzJvxUjJ&*o+c{zGQr`8G zy7<|J6;w7r><_gFs&{Le4&9d)A;18%x>Mwx;O&Aab!$ey!cV;B3z|;_JI{Zfp4&2Z zbUjkFG9VRcCib9lj+q>;!l9#7LOLsc9r1n4!7<(vOtXIUU=p&lA42n>YWx#D8(^W* zXh~87t_np)<(wL*8xY}ewCVIo$g?J)yiLR0lDfHxpr;YUWq8k&n^w+iy^cx1uzGP% zoUpBiS=yAT9CZ+qt#`fQVSL;1Ak2D~T8^A6^k}8=kmT8ByvqrtobYV5@T=GewlDLH zDqj~G_17EW_RGR7;5NpDNj_9=m+QT6dO5CxY+}oFJS%MFT$re<3l_!ow@A+%z33Q?JIYZum?5{fIJS z_)P2psSZ1>#Q@&`h-_mDgqZY+MT{`sh^-9Mby@cH9u_}$d!14~TY-i8n=LU2Xzg9) zI2BrZMRETv{@lg2J)aal{n3W60{e-QKU*K7^zTmaJowY9?6VCt>mIn!e0q!!+MVl2 z`ukD~M;X}GrNE)!6=zjlS*X|A7-dowe2Hrvf=hl zYfDdG>%%gcOjC%pv1Y*~E6p;H6OSOuTY`_J#FN^`1#3g@n69A1BK}J!uhBi6$z^mT zR&*Tv^LfE-sS|!IlJY+nPu>5lBv-sjMHxIB(<@}sI|WIOnZWj0{LPgI744`T^k8wS zH_saA0qQT8EY*XjgBPHQNCzzLFr7&~l~>$)2b9?Ks&E9254xFH((Titmr|+!X3RAkoPQ&Fz9D-*lj`B}M&wlLjA}T8pZT z+G39HBlo00kR;#GUU%y_*5kQ$3*^BJCoiE9OXu}lfjZm3%$lK`!M;&v;GWk z_7Dd^oGbdX79Oo>=5CD$M~CH4e=;n0L5}S1V?6z*^i>DC*ILjg$Gmxs=wZ zjSR*GLVydwdNAU$u~@N*jwDBQczId69vw;~vEB1>yiia`Po{S_Vbq)B!|LJNN!RHy zdGONqSq=mcd@1kvyI?n0DnH(}GhUa8V%rr`ZRo0Ft@u?BUek!7-vga(KR^WQ9KcJK znF-yd@3Dfs7Lw=O-~0XRo);X;m68!b#KacTv$qz;#6Tyia=E`8Vi|OxRQ_dubD{6C z_p^m@jV?W3>uxg-6a&zs|D=8zGc8oesZC$}1Cgad22`=-;1wR38ZBMlD2S}6QI)N! za-FOHc=3v6gP@1cqe}CZ`+yg5o4>?S!B}A8>}e;HpFmB^qL6k^S49YYrL&AR3mHR2 z6?#jGwMz1oUt=m$gXUZVCo8=&YP(IJZ@Uqr#p=~Cqun-%Fp0f4^``l9cE61X%hqEo z3Y1=YZiDJ=Akf?-hF0fg)TJ%$naw$0&Y8^Bmn*-bq^fr!{&K|f-F06o&#nxBz%VnF z9aS_QR^*z*^>_C>QU7D*y_C|T%}hrk*yw|1aL|s=G-{&|7OoKc%gq;X%}~OrWLAVy zr?4U1$k6JWkQ9t5QSm(tJSS^VgGWd8bVpViJpTk(3;2={b90x|=*YfP!ypbL7T(b0 zb~?o_MgEzaFJ!VwNnK@`)+u5$n;A9*)1rE$_oi51E8!j8@Y%O3!2Eu5evnTAQxe=> z>Q36IN>{J!a1+)gNuVK>&WJRw6G4GPNK3(H4liFasM zQ>Ivs(v!h{Fgql-JmxH{lz5ucL&@;9zjXA_Zu(cND$55Z)*MSi8!?{43vu-Roafo~ z89ft!xhuy#e*7AYJKEN_I4d_2xYlaK)Fh9K1Dirf1APN%k#52vGXzriNBogns*T?;^ zi)DJbv0_)vtvM4sobi>tk|+baMxhRM6b0smI%~5LQ-3e?Eff4920)wQRtrkE^P21t zXS~+DkarUJ*y`vvxk}|@kcOQZXSI+Us<-^caqXl;KrZL)_@CH^8{D6ntTDAQ-lZmE z%UwKDwwVn8+teaz>R;WG!q=M}ML|7ufd-6Gi;$SV=}Y&XX5ZQ0R$H@%O!GV_njbGZ zGaEv`YriZoXd0-@J}E#~GZF852YqnbfiL+{vwMw&%fEWDU6>2-p&#Qp*H0g(dCST% z1{Yq)oz+AYZEn+yojHB){Z>$UuewFX!#mQ-Toz}dXx1NijmOdB5fkm}mtaKv0Vc(^ zCXH;GRLd?TF}iD^ashqYc2Ks6t=VHscfFL;roy{yDVztsOLokbfYD?7Ab8NzgG+04 zVx|>NYlj%l+&zci`Cwdj1dXD(pxmuTBAKI<6s-iQLOFe?uL?}^g2kRN$ax`ovaWFw z&#tSQ)!)_+ex@I58S^01meT#oS1r&5q8QkN_ZmD`b|4wm z&PdwHd&Y}n(X#X-EIKmyVpocxjzq}f1x_aMVbSZx|r)gQ!kcx}>4xaVr>d}`% z(%h#$oDIuQ5})?7b0l;kHB)jF*PR6`)&uPN4vG9Z!@hrf-*Ghh#DWU+$H5V0h;-jy zhG?#s5aYtLDVg#gak?I8HrovC6J@0>gd*DZuWi_NVQrxiHaBZ{DYlnwR)dlD3-Ch| zH}R+;AEhRysAbK;dL@k|c>>OuH`{%kYB6Kv%QQ%k8o zo)5QSwsI|RkY?LG5{dxt9ok-ac#@`!C?1{r5gFp1V<(pHKl9m|5bmXAziP&7hFEa8t;R7 z*Yh%{$L(Oo-i5?nirph)9@}Ynebw%L%^!JuqLjn9A1xiSG3wf`7fdV#Hui`qeyYb} z38W-wk)kTj`O{>Ynr6(24bvLngD0J3zDXyNN!efe?qu!dYS=!Xi^ytdQB<=>gER#wDHSKAb|m7e!d6u%A1=MuKI zh-ngP58Vb?#m7%^meyz)FKJHY{Ge)pXv~XrCd}@q0)2mV&BVPDPhsp8{yeJbzv8QH zbi$24uiE@MR8L>(EtBr6<#;SfS^gGQ`;`fce^%Tyd^n|thoAc!e zFM&WINq7QfY31x&mG}0PSfS-i8CI%X+N=v{H3npqYpBrm%(b6M&v=N2M7OL4)W>fvyF=~Pfylyxyl?Ip$SCy| zliyU}7Z2;^o2r4n3b_@iiab>}(0cupJkoI8TTO0}61vStelWWH)H7R6_(|(pjVw|I zs*-8IkEi2io7}Vded0A4pbT4y)T`Wm#oH}tEPw$P0)M%T7L|* zi!||Az6l1A^RahI*O4c)clLaWWt_k8EU;Z$0CQ^Fz+Tl_P zdCF)qnQbI{`4sBC3de4^!d)kO02aTUG>Fo_KBqi7?^1|;#vju7dCNsAvvw&nw=>1MUNK5%+6*<99Acg6Be|o+f&+B|C1g zqAJ|pX@2sQjniQ+#D#71>cc;hlca&df5XofDBFjSC-$Bc%!-$ms(2&e@nGeJ(MoU` z<8HFBDU!zVXBi$?`F~hR%=ZB9i}u}de%iB%WAyOl-cT6ynx9ZBcbD-d$bx^?ttumu z6-zJ#(*?kCY6{fxKr`|qe8C3blT7f1;16Tom7k}E!}Vy}@tS@E{e|K_$NZCq=fPB(A?{4L%xBPMk1$i6gG0lT> z^FPlnQfPEGs4V$1h~?)=N5%|>8sv|F(lX`Qv9vL>ZaJugPPKRp5#Gb!>BcXid$ae= zI3yy%D1}IFq^GEVdM;W1P+z@hAuHBp_HyckZMKM;*0ACRKSD!1HD8GIv+QM;6}05I z+7~~LE=Yp$8oTJKwxP2VGYG)YIxt_A6x0l4!4E2SiphxgX%6{VT|_^ol`H9M++b9t z?cZ8oZ21y>#vrLkX!|%Jthh92=U1CKwSX5)O2n@HukCH4Yw>h&_5*O#T;lhDZ@T<> z&xq0VXrZ189RDy~!jcTA@tCevVc{$}xr>ZU)5zpqT;=D%ol8VO>F81=3Nd}F{41QT z^WR9a8a7V6x;S51n&qvVOm@rbNvL1A6*gNhY5_LrV3l2dTJ6kwu-Jd`{_P)8e3!4yvH;p1UP^-oxpMV9@rKuRwTyLqC8>_No_ zH9^b7wV6>T_1g>^1{M2+vq=h}IFwRyg=ef4`9S zXWZ#}@<`Kl!v@{QMuloFVKlA9f4XIAKNt322wr<=&WSNN&{xGC7>1Rk4dG&Gz#k$2 zBo*x*Us#lzP1anEB;1aNEo!x+GhO!t({|e!8I}dB`UPTZt~u9=CSru45C&59^di=B z*=*cmL)Nd+YD*c7q%hS4AG?H956+3Et>q%evJoe=P5PjG+p}Y-v-?w$GM6N@Q}R8~ zNS|yzNqDP7F~a6~0jCe>;~697%pYj!G*_aIa$R_D!Zo#&O<9=gU@4@S=m_YmK$~a5 zh}CUWnZXpvTj==1ynb88_kRf-usncIlgT{{KSr^0=iiHa6hj29LyhEk06~N060HJh zjfdRI!BXnSpVnZa$Vx7m!-8-Y621Jr0c-SqacffZ1@C`cJCRe7dcL&GMQ_j0PyUsv2NBbqYdo?r1VZj$ z97@J0{1=*n&6~qwT!PNqH_-o8P0NriBa^m4;4p}7t=L>8I4*)e6RYMGk5Wfp-{wt5 zw;KwNA0B#Ut9(t%N~4mZQ`5G7vwKPPr?Z`xgD)k%SY5=bVpD3VoOrkhAd}Q9-K7Ba z$))JsL7!PoZRdS1`Ri#LGL>xmpr>!@{Rv%he--9T3-3Vhbz%8-BtAwKVu9?r4p-%Z zlp6;2BB-m;o8qF=+;tHb$pampiBlIg_P@(^eTc8QY3;~|RrPpZDrq^X%j8hov!I8IE!AHdvh@m^8O`hXpmB4Uh6I5wnSi^=Gn@Y-wp;7G>lTj z?2#=mqz}n8u}3=m?h8O_S=ACY6-OIjN#Ed?T9=2|LR)#>OQ}WHjWQ7ety@7v@Sl_` zevu*581HyoH3x;b)E~*R$nL7~=JrZh2p<+twC(E;MR5GXcY-02Q+NGi$%iEj^z`|s zylx|t0gFy&=9-PjK35Kb00zZT86;RsoQXF z6kR1eDhkA>(Fc++9viUgd=WizMC0+tU7!2>?dvb>wKf)MX@%*Fj0pc&dFH6e#MFHp zijC_NARs>oy}nzke`$|8@-zkWHXI>Ozl^vg5<~t5ub{ z2X_K*(C;AxKm<=%lv*8bT?qrpl8(sF8T%~VY9n$ihIP1R{oFGEA{$|_o9$V(PF0qO zgODyVf6s3?x;p*431H{pg|+MJihmD6XV0t;Y5^9vIMq zG3sRZmS2*OIH><(d+JC|qNwbOjjxw0Gpdg+S4ASnzc0v7J}yPef4qs&LvH!zLB(Iu zUX~BdcH2c+R~oS3p|$Oyc-e!~GzX=AiuiMC^!2JrHL;j=YmOy#ZxyFBSRPBH*=eM@ zjvmhWcPhcU@M7#bE3O`$=N!1x!v&_7LOaf?-Jm**5>st^1__x*=ptkpR?I!g1rSl- zM{(Pe&mcJM;JK~E=Xz$hy#!q{zMc)qHuPaf>PHebpB}f-9<3FKD#XhmQv@;@kgsQH z13#8#DDa*SEk3ok^HJOOSwZt3o?kLu)#t!kswXqm-`}28nDzA+w9MnKV^?ZO2~p!LT6?&nq_V{~ z>Bs2dD6bjd*8Uw>N{`E=3jC7A4nXt%BUavYdfEOytpk#756eM2`(+gD(s~$Rir!U8 zpe4w`jUS^&RB#cKi>UKgk4_QKm6rP~WD)&@qN78Qc$}=A&~=n8uN??7`HKQ9@n(Pd zkndpk)*jLIx4FR|Cq*4jGfwAFB;m4w>x%xnTdjRi$WnGJFK*#IpEapfB}yfG>$OkQ z$2%b&Ye9?jl)dtCBoVAzWE@Ul9n=-pu9lT~s*OH|tdVy5(ILu6iR|!rd^gVicIksn zF_16J0cBO`{K54oz4GjRTd&rtt-pIwsgQqixkNr$;1Z9VuSI}cd?8+z#)z)F!O^(; zon~0AW5oNt$&l~xTij!fd874`w;{#L9j*yuiE1xQa+T#K{!;XgNbnyfcwRW>9~D>} z$7Y`*KaP7Hu+%U$*qVmeMWGZ$!p6Cm!8nOCZSt@4K7i4sLh+T~xC8Xj`!cGw9~(BG zTdNj^0BCK0La(r7cvnpFlGT(SStnzzaT-&#KakZ_lnDnNIe7Jn3Q$@MMJ7X`!rqeo zu%_(Cw@D62!N%blFX{Jq!SnZJsloD^^7*(Ti8-W@qQk}IPKWMt1rP2!mDt&eb>9z7 zC~L7OQ3l30xPCj|^cdeWeKVglR%hiRXd1_DZuIl=>f+-RSAEKTGW{2vaz+)WC*&H- znN#y*kWYjg5=&(NX^N3W?|auj%n*g@SD5GUbs7lvf`;Rljc5UmWSsij} zy5)A1E35EFNMsTozdhrvok8wMZ$#JJnn4SZpuiHdl+v|(y0ILa!UBkF&m3E_m~ByT z;n%si7SNYU(tmj|h;iqX4)vrfHcX*d&k(70$$v9oFZf*l(Lx`=@qZB*(!nm3_Dr=> zoKl%%dvKTl14k*?=qo+bt^<)^pRbx!a`_u;cri`vrjGrka4C=?<8{lyYync{W5LD~ z2y^K8{!#hwuqT!6m6L4Ds)9+vS!h(#^3$`h?Q`1#0?Xgc{QOb+Y{xG@pJd(qnVaQF zqV&nAOT|VtB{0M$51JrLRT$V5*9~L*_<)-0HT@|K z>caA(c%|jdkk45yNa0Z=G{pX+!SUJvT}4Q2qS^3;3!04AeRx2W*F#IITVdo~UYX`I znUo(oQL=+U$pg`PtzI51apB8WAm(lBP*z-y<=R!)ttlTA1jF~c!te)Q!X#;H5NLN_?qPJ61>P9&J1O;`dcWYINOSsqjRF#jqxM`ig=MPy8 z6Fc8Dimf#($r-m{NN#CeTzij7zU9pZ&bveN$q6>ukP++1{;i)sqgd}azXMGA`&K_` zFa66o@B%Y=_}bTRp>Mt`y+9_!!&XpDJy|pIpxtbf@3Hdm47-^or(;=fb0@XU#YgEp zPc>$-(97Op|9shu_F>HSEpNat<2D)1gp6)j8h?lZ&D4#|SpCP~`?&rNbGAZiic!Q< zpl@n^09VXb%(OjhrSCWqzIr|u^$z=9`T{tdtif1w!xunsC6i+=Z7D6uU!xW5n$QB# zLRwp7{OvS)8472*Y3ENhEHWBXuSQVU>i!Q?XC2mb{Jwj-1xZmPq`MT9PH6<`P7%q8 zbZoSgbT>$Ybc`-hI;4B_l!h^CY&-jY&pE$y{@u0f+Gl@!-q-uNpZk8@jUc^$?cg7{ z=ARL`A-g&E3rd$rp8dEZ0);|)UFnVwynBq{P^a46kBa!uCr`R%n%Ff=H+y;puU!)I zt;56C{iK4D3XZf6eMb$rpVDCT>Y*u^tDC^{DTIf*o@r)`bb(SqYDO19I>mvH)svV! z$3~e3*&Oi#{@OOAv7Laz!LEeANlGqx__a6Q97HDG0DG&kd=nJhg;yDjvAt&0x=~2v zx2u0P*7ZB|uDgS3DsyJWEOjXNkA;nV{SxgD)O94xt(S_B||1Me&{Be-Oy!7qFKSjU_#{Y!*_u18o~@J zucRfL2MyPsDmpOrXCBAvS~#Z6p5W-tOaWj9f%(T{UC#pdxcL#D5rdxc69cZ43Qv7S zY~bu341NC~*4JlkB3p*G;6-c#mNJ9&-%Q!YB4Q8$GDRSrKCjh4o|YBtdi_GYdm91g zr{t}@)9u*!){_r-oa8pX_9bBs2L%5mp}4_2B7p;xPzS6}MVwqMhm&Xrq30Jll(BDeu z3~$X+-<9sq+CbI^O#W53jSc*gPL1MMT!WRio$bd-x{>KlzD(O}Oa0oi$)#iYh-XBP zVQY5W#q2DnzUs`XpwsbCgDb7bCIidG(q&EEEy=6n)!BllRs1cZVmk}I?EsE@OLF2>}o!4XY;g^;H$H^+g)Qf zQ6^En5#Xp%RZq}30teZUOn!@My3y3UGGt#X^cVl!0qqCdADVyEu8bc0fJq8BHo2=O zn!tK}NF$^-ts_E7K?iGG<=rPwd^Y*hu}6U$X$@!3^zot8#`@Re^vgGzvntcQHKMM! z9yx11v(!M`R6+ukxw75?`@6|^&Nn;WWuMYVc})FK?N)yOFmL>P*?=YX7^}iul4C}+ zdIpKVBVG6n#(QGnA7G=qn5O&apWSqj4J6l8$^iN!)aiSNw;jnD7eVqLE9g;*KWbKc zZx!KX@zX=QQ!@Iu& zm3|;jz>otSWR=`6Mrag0vwlT>;22e^1d%hsjX2iuHA)WF(U z?*ycFTjE3HXBz>Y(>G}KL3+1igt*&+n2Q_u3TeS+;|N)Lk5jHaSg&`Ywh1MH83hx~ zdz*V7F)GX$Z(+V0sJP7W3iO=af0hWaaAWS48Efbz|GAaDzkSiL(w8v&3pLrTjQR(^ zC;oo&+%Jq9lb2;!Q@dla+|667dS%>O(aQ*{*nL^-VhDVCF$fuGHSB=%t@rH=cDzX| z5Z;(Jd9>-SK8WX4F+}u0^`ez(VyRaxIS4y0KPY5CXG1=bn0RV^&1=iMwZ3twn;Gv0 zf7v@>aj4@(Z1XPif^jn=H?Qq8Hxb7jW<|}TJw1l7piz0WedHIO1;g!nwG{Ih-i3Ed zbrra_gdpSmgnoN0+NBY3WX;)M*k<~8OIzco2<0V6P2NzZ;40cBTK9~W>|kSnWy=z9 z1k19nm@l&aIdqL!b~9@@eYCUaJK1+eDQs|V0+xi2llye7avtP3<6uO(j#Gs9HyNB# z$%V_ch)MZCkn0w3k>h|_tfIQ3v2KYC5t3o#+A%>e4U zUgCco=8X@+50^(i->li(i%;~ZP+*cCxhqN42;gd`eEaGve*;{WiTXG*;xb z|8alx(?do|^PPJ@?fz1m8b@G7}>Z70XIFjT65~2+meV;Lzu3klESI8ns&$$1+&a{6bsIf& zJwZDHLsMT= zB)rU^V|SH`kb?{r?{bNJ`g~G-noOOq4DOk)ZA;1|X`L*1MRx2Tm}P3>Z}xB5U%2@i znz|~#tGB(qnI-f|XuvtD+odV>6>ssJN0B3feWnIoR%-D)*B(YQNqq)UaJnW08c)4* z#;wpSo|3g*AQDe?x>by8Rz0jKQljerH)~yhR%!Yd|QN7yFcP_@8ym2J>Hhp6w z4Mv?v{$0;yxPmkRIcGsv^49mE zB!l7gD8pXlT3`Md>h$aYfIjI%>R4VUA{*s?Q=qme3hrGU9QNnY!M7A>ThM_c=&KyE z0{v>K-WocMT9F&S2}a+*%7lP1iNO!M6!uR*p0uHg{sGSHS9k>9u8I0S{5s_68YICc zEn7A)X;;D01D@Ig4hSP46^ASAirc<1;4^I;X^aiMsa2Z?kq`~`QRiSOD(ZI*jbEkN z5uEAL>9^w1!f&K$LSlt~)?DURdvQq-ot$?s&o;#uA*nAC6Nr%<*mSys%Zl6*D=$uz zLOxb`;~Tevu6;(06nIBuZHJ5lk!}bao@i=Y?;_M}+k63KvJCE^8esfLnse;i$SsPg z;-ymeu+uO16K~lQ_!;GS?{48q%e5wu?K6Kr_kN?wZtD`8{B1SZV-oCLsQXQk`%`Aa z`+_OTKk=43%T=3#m-rk<_@tLp6h`NC@(5?+aH)b;<};ZR&X>e z&8$%_lYJYJUO(?L?jW=G2D;D&>x*K0y>vfK$5PC0x2pVQAx>TIvBqv-dCEi1SxH7! zPc0-epR}Gbc1PfBS}34LPehKzD&A@+VRU?`u>iYo4{`qe>;^5*-hST>aGYD}IYG2X z_PDPP8MGWWV|z@giNyn8yxU=3(Tuy+zvK~28Ruk!NJsqeY9V)=Coj;u=To$gGtH-t zB38}nnF2QthO0jj?EZg7nNezEg^Z-w!J>c5*dIP7PkjBx!w~g0ggqKt!{?27jW&`; ztbD%wrLm5)?%coCFHw`M7im;fB5K&u@LBF#9{fs2ZJqIa{27go7iSX3aBsRXH9~8r zQKfwImD49>qe(IoonNplZhQUhI0GUTra;&Z>b-I=Ah{|;5}Q;0;>$Gwjw|wz77;_f zAx&`9Iak$_nxJQPg)KB?B$j8Kq_BF}j)oR;aG(&khoFg{EJJE@nEv5ZB8c{fpk7Ot zi|u9H{o(V?yq8gVEAt6XRV}?9CVYQ$#lO;hk+Ul&cXu;8dNQ>^DxPsR>f3Rmr{uGd*Zvo#Rwh<0p%v-dY?9LzEUqFVCG(6 zG`&>k(jtAwx8F%B7Kfqn^xkJUVu>fB$(NV`$oJmpq)`3BoT|v`t+2(gMlq7s!)+`_ z5s@3MPMEKBBFXIVf2_BiGKWwqg5iGonVMRMsAUe0ttF$X>j(5};Ue!x`hqC-i)h`f zUd22PQ8`X3c{h9TjJ6$K&w_7`=CjA683s2JXkadpNodHFUQD%{bEZu-lg{JfqfBD(v%3i<>VmvZ z`0h#iA?!OCDh64C1|fCqiq9{zHaMSKV)8#4^#Ru2=7>s90(1Ybl{V~4?$G8U710J_4X{c31H2{RT=Bxx!`(A^~ptI+DkGi zj3CBq9lca6wJEfO>;gO%&Ji=`&W}3m&A<5qm4L$6IfE?4e5+iJ8+mi`fXi!d_#k@! zb-`f#vsgQ1Usg=GJ(eCAVFT+d%M)qe;`mRw;s?ZdgbdS6ey1md8OCW{lDr3qdUXkB ze?{*WvA_wh?_5=;=CHh<&Z=+d;q4RvMyVk-y?KV$x*Z>gi^-+me}r3n0?NfNwf zdysBEXP#7TJ#kFcrVaQ6Oj_(Dzfa*Pz`1M@wbN+6ys?oEcIvS3Gbt~dy>~27D(021(G7kiuitczq7H9%DsfTI3BpRzYdZH2 z8Dw$Nt87d0gp-8(wXV?Xt~83DX@|#rlm269`#G_?ai2GQDvgUka;XDMHv=#O%ky?$_bvWqSGId*I)sGudT0r?l)V%>1+jP)8$xnW&-1A>FoEAYw?q zmjxWSR*uOuI7bBqs|b?OLDlVbeJ6`gi`Xq0-?&~M{Yd?hxX018P~s0yYFRD2J--}u zX2Vt;P(%|L!pJJe}(01Czt=}+>M)-%qK_x z?z;e-7osZAJeWpH5IUT-H9+}o#R)FXXL!uHdoOx>Lh3>9F1L^;=)Hs z5$(EDbC9N7@-G>SJjxQ}ln-yQ+0sstu$1;kPJ~ROm={TV8 zAtZK-L)?bWZ|{DLxp@5zuBlJE)i_)cp^GzXJ#>#kkrKFs`GinL2-5M^!PHWUm4_ZD z1m%-1`!{HQ>&7<*$0VCajeLIL$3G)|;qB1V5YMRNW*w9H)hbbCA5)SN)eAU@3HQc9 z6=HV5{CFRiJ%EF2<$Lc6`&DY55M!C!K_?hp=Oy>OE~^ET#oi7Z_3>HzJ|evdp3b!9 zl6K<*3?mnNUF?e2oQI?T$ITyRWsmdK`Q3>)<#B`3hd4R++Q46Zed>M@Alg87e(!Ct zF{Lv~eURajlQM#Zc8kt~VeZ7>#S$CY=YQg@2^$~r42`={HCbc2vIQ@#nE^L^s5_1= zLSTMh_&~1=V7MCGcsVV5+E*qh16}Kgt)k+xf|}KAJi3;AL232xi1)L-GWRF^BRs<; zBvf1kP;Jj*Q@zXCAGpv5;Z(e-w*i|I-vOv#>C|LiR)pdt42mt_KAZ_BqORj=9QP5}5ia0AT8arT7B@Pa;kgEy=rYWd;}lc<-lMjs8? z8z;tk_C8X0R~5Z5oQXv95G3~`}Rtp>Z_PWOd#Yz8Fw8IU#LUQqmATwGHw7+ysn z#n9HkDtl=da%E41_y79rc6C3--+{0VNX(nE6H=W#r=irS{h*eb6J!vjvlr7U z;^u`rwy;e4SKVHIW}zzVo8GLR*j~8n(k)l zPSon{ zs1Hjz^7*{KhR5z?JJjrMrUmIHt1w<}uTN3jtZ6gI=$Wocbi8ieEfk)4C>S-p9L)=Y z;$>*8eFQhOjqEOR5z(oS;Z5)n_Nsc)r_<;NW&;OmslmbACj+7{;rv^~^C?v-nsSbK z;$4vo64Q-LGwTw?S&p*-i9ym}@1;(kI^*nanNa`o+rLfuYwp;|j&=71viB8hh}20u?@6uyjQ2Q*IgqVS&Cg}A_c)1234<6RTkBZCGo(%B{LIZ0y$TCC z&&;DFaKTABfyox`jsmTUipsC_T>?@l2ymtzkRR{k7vKu!wzsJ?#PYOQC$ z>uQ}iio4U;z7M=1pd=84pT;SFLX*?+qTbaMP*9Vsg#UK$i0Yk^qSxx3k2HQBU=2U9 zU_W5IAzJR)VF-AJyO`M!-?M7+7qmO>Ms@h7OIa<*ob&uGTA#n-Zi;2bk`EKw>~txy^Vo&m)Y`?%ILu@8 zf^T_~D#VO)&$#KWNj9(cXUsRvt%57sCAT9e2;a-C_~b%tOrRq|HthHb(~(c~-k z`e);M5FWJ>^2wv9Jwx2TPBny4o>Hh>OP$k&$bE^b(N~1D$3_H-({QyKOFh&6fTj5) z$zjImIeM?(p@C*+U$qr}+td(zdy@pTu_`Au{IU%Un6f7PTDNnu!jAh?zpXm)!ll94 z#%!)zs@%^f(#s&1!nv>EnvB%sbhi5?r{&Y-Ub3CeDNvpC;Uy>vYTXAy2HUAm1mC`H zzd`^}Bg}VfL693Dv$?r>_vIMh0~dNUc+gQ6_7t>l42lFG+5osVj*iemBDdGCUq6AM zNv&5wxnW|o7e3}T@~Y0QUy}m4^8#n@yK6}>kTlkb3B3CN`bs@LMhZF;b``3Lbmw>S zu%zhRxhf8Tex%bGB~xYCR~fQBZ{oR5TE%^n$1K$s5WTx9IfK>MJ_dTSg`3>oO(`o# zv>N9;SIBni@+Xy(Ix{!7#P4{=Efgg9h16R*8gm?WSKQVsvfJqD@1p~b4ZEm<`X#RU z5@LoGo;c*t(POpDp|am9%@|De}IA_=Zg4%9__!j6YM(iD^sefNY@ck30yy)Lqzn zx;CR`2~7|A!O6JEPBZCTzh{n9kV*U|9=zSOv;aHvdgr2CcO*uc@vQS*@NNVWJwEoo zlLtEfhKtK=ERUywa|)~MDeZWlk0M9f#BM( zKE>|q?ma~7q|Gc;Wo-4T84%^r?+y7auFD)5`9QNZd~Bj76POUvku!%$S|)c++W#k3z{ZDhHhOUP ze5n5E(SzlCMXKMYZdpCEm{G{F@nL(?;VG*85rOwtj#u#u8@~HH-6FIb^V{q5DC0LW zslSIx%OVdCM9sT6;}vwFs-p{$S`7N+oHzXj1XsKaM04XGQ{#tuR%Y6*J{VW15vX<2 zx#y1)WJr~!GtIZI5z&;oXIhwYqj0i}vV%-g+d3D8wPbQA4hVjeAG`uQPg%r}l>+00 z@1@<;O6oWqavZ}$4DEsIAF>t+7{~W?Iskfg;@B09melQ8^qe87t5b1GnTjz=#Cz~{-)6wDK%&c=s!_tIxc$q4 zb;4W;DtSXt0bDaSJt1FTll+IJb{<5An7%`P;d zCttbO*mN1aK`kZA70(mV2@<5?>2_fDxSK2>IxH-cz8Io@=#aaC(xHQIe1l)ho#V>& zlL~eB|M#-+P>Eb6#e z#*^@}76?<$0EWQ=Jii5#i$Niw^*q;{y$TT)nxnk^3vI+9M4lLPTWT1{rMEtyMn^fT zWj>f9DBIAEoi))QC^%Cj#3!7nN=SsGcs>p%2eC}#KYkR1&tRz8!^Z+v_UnE}3_lIg z)vSJ`y2%xmuJ?_^2fFB+;-gk9$+mS)7G45Hb}{0(YW}OjQ{}^xcdv<+8v5IP-uYVC zyOPDKO8|$lo zpYiMwj@Fq!kRgJwddI1(G@p`=@Q}-rp$6|3;?}C!#K&W>Pq?<-BBO!`n(;5}4qhad z!dfVHc~7!d4!=ukKb7TfD*WF72GQT{PMrpA#FZ8Pg^6~LwPHKgl;5Dp&j&^K*uua2 z3aee6Fn_)GzCEJ1LAC=l(7n<`bK_{lq22^YcP~q#i9wa4`Hzv-d$8vWc!Dm8KBta|I7*A5+$2k-W(-bxOqQ z)C;bAJmZ$H`$jPW2!WyDCep3~HEX{0@Qv|aM(npSF#Ixr?eK-9NTQfCd_1AvGqFLn zo#32!8MJbJ_T0z3FEn(&rZ?CU2M2=Nj+g0f%4jUIP@h4KA=#^1aadWux+xo;@^Q)U zTDIQ}X-GA;eiRxEdwP4BOR$PrU7g@OyaePXz{+nb5@42E9RWqX0xZTNkO~lremkmD zJ7lFX*vAQSji8sZ_Lf=b&G$Y_O|-qnXHHX{0;o~G^!pz@XIB?*hlJ3;!7O4K+Orz+ zAzVR^!$)t?Q$UlP{^c;%AN5BLgw;8DkA}+2>LNFv6nv`GDp((BDyUdU7$|bGw<-vy zB48vb!c&vE*PG~ihV!OJDQx(A=X@~KX4h^BKqvE@eJWAsq3Nm+!WdJtaI)e>VK-FMXxikBQwcUz)t(ee^*f zy%a=|(Y04%kL#X$tv2Si|2#0sg)x-=5@LHwf<$%@aZb zt>M;C6;ow)SOWgB#mZp^0Kf{#P4?x3@iQX4U%8Czy4rMH4%w_A>@89Q@vGiluaw3l zp*sey)@gpfK`>QA_|%Lu=zN~~gPUaG#1RJv$&BGHY$l!|=3;w<>G@|h8*kCFV=1#3 z^UdUYGy|Y};QszzX=77Pvm*e`TZlY%yt~Zo>%MixwB>>~1CGoyFx42AL1>{MiIBJA z?&?bC5GWEMQT#@lHHbN};k9REEHmX({!Y9->Io@!#Xp6=RUSVRlaA}TgWSMrcQ8G` zB;-BXff1{^M-;@PkysnwMg$>0Rb-xV==7jc&V^``W-ComNhj|qdMSh`)#E-Yhkch? zR)hYef4;_{k^?z767skH8yNXVlhKUQbe)38DNeqU#VeCufTT&l(`+Nx9LUa-pi&eT zdW1p)2g4MK^yT$S*s;e5Yfr5DRaBuOt$VcJUaeo8$sKsB@xB~ZDbZUYnLT=*JopqR zBse!%h@;%*M}MJ;b3lF8od;&MwnJIbJhqGUek#R$W+!h>jl&^MwGQiBBEqkpdi|^X zn#fxJ7s3iAJ9G0Gmt{q~CDD=-tE1Zr->S9X+Ax){{$Augf5Uan`7Ty@EbY2`O%R0y z&`NF$GdcWcJN|Wfe}UX>ll8c%>|I*Z8Nqp=NTKRR*d1F^FVUKHllcQ!ND0IU+RVgo zWO_hU`aX4bnFkVs6?(-}j~D-dW5&@@-N2*G#rk)(GWE8ZeN0Z~5%;hxKu@<24w{$J z9Yoqy#%ND6CkB8Ti_jj_^g~0+Ab>|54^8mU`Nja(lgEOBe0ay{-#w$U09`8b10uHD z{KJe@_OxEY7Y=n)V85ymAxuN_Ey^XKSyR4S>0MM;-|pH&e!q_Yh7c}d$QCr&Hww=Cg^XkK=2erVemL$z69f zc7E-h`ZAmehd_x(en>=-+mdp0V@U7qd^|zg|5b4R8`G#)AYVCy_ zC@c~#zbgETW$t%cBf|608e~&YAn)%ae>eE-U(nFggX++pu@ot7hA#kuU8k$&D4UA1 zS@|Vt^GfeNq7I9t{%88I5`o3ea%CxxEKBw;V!n|dp7s_$%Y$3onMjbO2P~&LVAHV* zatrRq;Qnn96E>0b#OzpS0y|y_XE*kFc3_3X&8PQ-dCg{N_>>9zy>ZeKkof!THs6n` zA)DvpTv=#gIEo}Cg-2{Dz^fqC%hm>~MMSM~2HyQT?(y9|`Q5-b3wsSr-rO)3t|*q1 z2;J)>68o}{wD>?zF&-(Sc=&`=Gt$6D*n1S=VpFY4V)xzFVs5=KTTEVqAdN7x%CEV` z(O8PK-Y~&swjp}rT3_l+|8;h4e{xNjvG&`VqgQ7}oJ=QANRx3s1{0)AY`l!QP=*--NLG6u+q? zHiCgXPs;{r8q8nNv>5lq;{*lvCSa|koDIj^EOc!erQ6#XbgUiPV}IiDYqfN%xsWxI zl2m@E8ti(JR-(5xMJ!~*^CdIpeT95Q!bWLpPZ-g3-wvYv-}2%qfq7sMseAT-mc0 zr*RVF@f!nyRmO2fg)~_cjyoq*$D3?Zj6fenU22{LCI02z{=))kg>-EN%<>wG_xiTI!eEp3Y27GMPgZcN(yPk<@HYZDlj>L8Q0F z1rccI8usaLyxWBm@3`~+G}ib1-d_hgx@wUi+;-u{-$5;;OT79mpn;_hjSmGvKn8I1 z8hwPB0m37_y$2pW12m04yOVr^q;JJ8OKZF#Vm3?nh8$S#Gzul%i0!<$3XriL#CkDQ zqe0>4;)?M3_jCkc)_3G1AYao_6SvH#5uVRBto*%VoIaxG&nh90Ct+`1LIsoluyU_b zPr;|Y{;6DS&>D)N-`8Z=D&Gva7BOasEyg!=H0;t3le%z*5fp}QOGG=Ty6bLZA$D~=++E?qY3iqC%9W9*mzcSMU%i(O{?m7W$iarxFPr196y+sntb zbbmhyC*ctokdnENa(P=RRFFC-94c%wrb1T~v#HAq<~9Eg)xUB0c*CxGHxeW>cgK|X zY7aSfC|5Pf_tIY2rxn*8H^gbwhPoA=T28p;x7uw7vf2=^ro6T0ftAds$w6e9;7|_AvyvD2Gc%GEB}qBKOYu4otk6t zgy5-n=K?|BTt@*1H~&PFT zPc!K)n;?;4EsG`XvX{yq__4keI8_Kvl^X24J9DpB=ruZmG4g!W zE;^FJxW>6SRhVr3t);bLKWov!@BA^G=vzcE`V58uLC(yBuEXVS!ynEm(86*T)N%vN zx46MrA$LJjiRjxz7^V;xc!fX)n|Y&mXgGdI^s8u*I4xCrs8wzf;QbAoBNN&=o%Vv2#No}env@@Zl_Z`jRS}Tn`1DE6+ed=$Vf;xIbB<>M9XP< z6i4*?*~P_@<4YLH^Mkqwmn)S^=Ah=|*25|p&peLpOR~C_xodRTNjtyA>){0~B$C`6 zQa6U^>1rfbHlV~5y#uyR(jmu5YSHOL4i{7&-zXZBQ*8>_6(xJ|lka^K)uJPWxG*r- zfQWoepq+tKzs;VToiaEvpE;MFzULHTtbE%$U%P7ji(B#AgzP^c;#qRY#MuU^w>yQD z4w$HchXTUm!^BVB*sRAkO}y`R;znx$oIJt+uV*|u&ctvPJ; zl-8S!LyfP0)_x!g+7tcEc*sngz9n9MojM3JJkH>2=h?SWsH6usj>AYd7i9oHnXy4M z`nA1(3wgTkgt{3I6=kNb{tAjza<%i||2?}pvBb6d`%_2jB-qqFnD%z6@K*tVui;gA zX2JvjMjFAzlh=lw)K@KAA6=>9~a{)ypr0 zw{2XX)R7lIU-Rf#J}j&;@k36&-WH;|V_b-O`A+J&<$zV>sg3hOMX08I)`KPHT#6uR zzd9@ASPz!1^DUVk43zuH`gDb^xUToDi9wLu`5)MMJYsPZyZC%Tgf?U`Z_^mrWytDf zO--KJ;EA@!^8@k6D&tcGGC1y=W5hV%^Vt4bY4gA0^jqeFns&xRn>>WBH_jqqcl-EF-CPekNN{r?d*PmG{u)-*UvjZ1V0SO({!hn9AcB z$LE_h#UAk&)4_gkd8~w1ixydO#`0-Wy4NdfucW5|Z}=ubKXh_Jez-eeEsM4?W=66a z+30FmhiX-cq}IG9<-dBE>1Ta<8U9ZZXdx}ugu*=TWq4I9ypq+D$*kOuLk)*ceO#E< z$-{ev%4S1WWGyUx_I|sv&9ftw|KGgx>lDX@6#?c0VR08s^xpAgy>JcX?(?L##NXoQ z`?nz7BpqkWy=(aXaP?6h(10N%)foJG)E4h4v$ll6W>`CQw75MtU^*?-RzO_G zME)zB-+PZ4mLY<>t5f6Erpvs0$c`0mSGY}*9DPA~BvN|bO?qzt`k&@V9L%}3Er+)S z1)V~dS6A&^T;isIr=Aal=z(DQxmW+`0Dtly?fd?)=3!Lsj*BNY4AT$(K=A|~^svhe zjRO6Ry1hXogA1#x{SLAnZ~rhO-){!Nv{AX}gFgRusf*k)ZVO{!J+=gZ5$DH2-&Qe!>LR3yMgb}Jv3d?xMh-ut<--yr!G3#s5YjMFO)5kFx0aiEl z2*)SLX29(i9b3R@7d_E>zx=!?fpMA7!pJ+`)s&ETDGA)NCk)GKFnR`=?svC_8Jiy? z*Mb+0x)g`_P?8ltn_r3?=Gm2q-ML_Bn@!{NBh(KD>lRTVz|o^5a0S-JyCV~CBEug+ zZkfcptuSTQT54-h__+w}vh=06&Vw&&sS?|uoB?!9H2K7y8Mi?dG$C0VaB9Q0M$5{R z&8}p=9Br&?H9ac6EI`zH+F{gnuq?88S=Cz5ZL0GCB|i28GBRL~G5drmY>K-wd6=bl zlRrEwK2K+DJA%lZPrr2`kBPy#E6v!PKI&Z;EGElf3{U&XW_=JszoIeQa(t4}ee!?u zrFafn+_(VSOfZuGrdh#fuCFg*pv%qLS6RL^(H0zO-GwXk@W|YK3l601TCfkB6u83(iK#XBX|9>DK{4mJCuAjyq}if=(4F3>d%<;u7D!^UgS(4U&^a-xQ>Z0V8}fX{a3{7KA_N< zEDv<{{%R6;kga7<5`MJoe`(nZxam$nPcLU6*a`I3ijpY?7yv4dDe?-Y=cK(UZiARR z=idDGC5p;aIu;KeM!3%<4&(l?lp{Jv*xm>YOif4Z2P~{cN!3b{%89>fE9_I7z{jwg zpr(r0QiJXHmV;#nyp*Lchw37aOyp$6_qCkvNB(oQ6WIoTY!(<9Gel2kwuJYTX zkNUsMXUCq^ zvvuh6LqiT^HDkfeanJ}kPU?d=f?T_XZpcf1><4-MO4^UpyeHQrJ}6s~#rIJbD{PWy zQ)Hj6sr)nCm@~UD zoa|ejFJmfpoTh@(3c`&C_HsP#;EtZ*J5^mtNbao9_%kMBa7c zbO^(p3LN$AGsOMn``F_jV75-;*!dqG8>g~>+;eJ`GyFRC3dZGqNO@Cgi`T*Pze?4#ot4gK5Q;8?(OG437EvQ)#MDZW=0w_6OZY z1!qAE0#D~VgD-?oZ&4-azj8Z?=nJ{2%}pkuo-3;0BLGrB_HI;1b{=@Et?xxaSLyPT zgNP$1q&O|`HlPNzLJr}*n=ud8=H@ZXWJ!|WA;AXX;ac~r`1ZYHPhN$#tm+h0=`}Mw z-bOPSjflA_vz`3`D*odsvx-qr;E|$0!medWy*RW^UwqE&uA?P8))4F3anqI2AgVY{jnV5}QQ~ z>K>;>kaDvbGZGSLqDpk(jzJxWO(O*j^@dNi<}LTC(EP3PYovpghpUBlMH28T z`#oiem9|DHpjw~WF?X}B-0)`Tri_K%G_mu)@Ij*3gX6ZwwI;#gxCo->JG1y*0#<`e zB1=Tzw5R7)IJak8C20HyWMNEE)KUZ44hO*{!BC!QqzpOlAmXwsw4#@^S_uC*Fuk4Q zb;Q}BakOf(d$ZeiKs_9p88fW)&&}^y-~>sCY}Ceg@@^e+V&jZVVn-(IW@3V$ua-)N z>+gxl4&sS9T)~*hzc^z9*1J0RU<+V2MJ!nL*lH^HCuXJc5&b&H3&;2??ilbUdNjCs zr~RcC9QDu|Jb}Uq#yQh>ZSIudJ^QWt*96ZmfZaPsn{aV=N|?T6#VM9=-{X}7d{@4A zg}#x@;kk1mE7Wr20sOq&jyr4fY$}P_QvIrJw!6=|L44~L1y>GzDwUOGUweoxR*4z# zB3F)D-8aA-w?SHXSd3KAys1!66w*!hjreNci~l)>p2t4$QxhP@KE$@N5r*hx_&oPZ z&m)Ie3%>t&JI^yR{L;9{Xm2!cXT@Rm04o6a=8YG=9rmd0>UQ42rVME-lTYzn*7pV{ zehhNtUBF5Dzs@US4W_h&shB8xH>3*Fl?>7NYpdiVcN;TvxO|~I7 zr+#0=xaJ<=OPC`5%_DyPj@immzb}tRGlLLLJua9mT$3qI`)qn|ji-#4Y^@jnpSksE zZ2xm{_eU>SB>1(9C8zhQU)1_IfxHV_7Pw^oSo{4xP`Vk(7st*%avdG{7+>Sw=pf^t zlU6(NOixIm&;E0Z^(s_SW!xd+z0o5~b=@ynjJ|#nAAK!1s7DjC^CAjU?I$6PMqB$J z`J2NseZeIo;OrJZVCJOK3KdtT>7gerSn-QnpNLnW2X!h;Q>+ z$Nn=+TwL#s&WJ6E-G{0n*=O6w2o%$2Nogj?l5Fyc{MZmR;HQ-GaxaVZHt;-=7%=+O z_LC7Mizjni%8M$YJr za`_MRR4ZXN^TuQISg<14;3wJ&-7i<_jq_sE;C_c|n` zD8PtRmg({N57uKY(d332$l)0y&f}X#N}1j~D&JZ}Cj}8vEisX)1wVEn%T|kgBbHMp z(aKWiGfSgdD8KHsD6{vk&sLdPyKzi$`qg7V3on+ceY($R5SyFVrrY46dQ5I{d7 z)3f5didKacKk zl7|jo4%t_*S|pJ-sE!wa;Z`;Ev|+)ceM=GHc|lCMtO2P1SJO~N^w=BsyU4}Fzi?OK z)~SmxwU1pnqHxr*I^A293dHwT@-UU#3xZmldx7@hW#Kf{F;zS?`jE6#{{yTlpDnOO zDyNvgqn+(PiPW}xf__l~xa2QZr+2&!C+={5CBJ0;(HRB&pP@XK80=@G|MQMjO zRVAjyKj0mYKz$O_Q%{Vv>|?gtTifahN%IlU^haC7L?p`L1GVYo7M9=tdXI3?IxUCa ztt(FZLif_OR!t&5ehlfT8ijqG7kkU1EuNJ_@~InRQLePt#dyNEON%>vm1VQ^d;fwm zjx6;XIO!T#;D|bs0){LBi-E&2N8|lcn6>Wi1Ajrjy_G@Ju3!ok|=v=6$)` zVOzs>{M>b9Kt!)~Yn4fEiG-7`StY{jo#Yu?111V=peOxO^ix1F0Pz}Dp{Y8y^0lQ= znaMcgT$A^tx)Fv&CJOMXwNB8k$|1n_3Ml0wG)h#w8*aV({?0`zIDL*Z#%r4>#crk>731!Y@%AE8*+$s%W+&A7@kz=+N8UO zD_-3Zj{U>I8imEM&$08!`o(_iqqOR?XsirsGIHm%7{CoNphR(@EH4r(BP>2HnHn2q z)bQt!lAxtC!c32?kb`v(6{2egA5&s*sdV?USz;?fEGpY^X z#M{ywYRriBE>ufkuNJ<6zr?;(=|#P*-?be4Ezc4(jPO_Xb01r~;>#oNvgS~+G+&lr zFDtd2m@Z%&C zUP$f`H&PJ0mBT5e`Ze`64%<#%N`L|HoH!m`$K$`iEp+h9ze|A79q;4iI@rK}i(sU~ zX4#mCrIz>QeuZSa!wX;Z&&Yb1|D!qwkS@~?2HLlucQM?e`f%~S-D4u?{cae3szXJ{ z@i35~k6O(|cqP%ioMkQttPW!m!=A@$8Cw*uyA$mcJ4)t1@6=cqY$K}I+F%v3OFGIr zSNydE#19AJ6zEYh*@0){@<5N;V`Or~qDp4aUCKBmIzakct9B%mj0|-N!m=7r=6ObX zobkVydds*b-0IHj`f)z))v+v{WKl0X-<8Bo+?SU=kvy_ky(%|55#rKFalC72Clr!L?5YBk<4GQi{ z(U_zSkH_0IKbMfx?M~z>0F)0-jmpZs-sO`+{(n?G6}t$A(Q3y9pY?wJEU>ZJanU-o zI_7m$Hg`v}lY3%!N#C`WJU&juYjK^I7p+k}iEBAX$Mc=USklv^9)%AZG#LVu&(HW7 zr|e3#zc;&Reyd30ezqi2p;RDN))DMAMZ|@_@zF3t;6~F@-pDAK7gI0pq)UcRH=tvd znKKa87PaT@8u# zW$YmI+h04RdZuiX-4w{M(E)_=2k%Sw2k2c+B@CDZ`kLytwwy_Pp{4AVlaJxaIMp3d zi#lJs*|vhFM-XdAZv<~tXaa32Ekn&l<_Ql!$u*!7lppbr^mKuFxAQgVrC*{Wiq?&6^?5#|#+c_^1&wa9YKzl@=_s*HLU0oI#-yIBMn${5>H*`MO zFMavjJG!BWjE^7EHt>FFzFJ8^$oJ#wQQpNdrU>n=6xV-S?6*`?a-0!bgB!EE|Ekjd zkOgZ`tG+(-`_b|Qx;M1_4!IAbBn#mSfQV2e4~=;HqLy@edxSaOIw*YL9Z(;0Ey%HTT9i5n!#_N z_|zi>^wfoL-umg*Q^R*IJ5}3;txte~*IzJl)2rU~isPrv=Nk4FkqPO0ltp=@qoE`k zt)J>owe7{$fT8}XTsmD?e8sl8(y0EcdgJ!tUVTvLBXb(_&N7%kwz54Rb)3zE?);AA zx{{J+lZCy(j?g#(GKCeOd67HVs@xfkb@0*D`YA z?P26^tvH*9UGtaXhfiv;Mm_~#)f6uE5El>0nN#z@32L|OSHl(t%k5S0{d^|33EZ|r$hH#*X6TU3cmT#Wp4Y{an`;Lxr6HRwUrVH zuPy#5;RhZu`7SOCdlk=GIT8MxYLJj`kiQBdQFGo}bfs^h9$BHlD!epHc30L+9?6|Q zebuM0AY&EaQWSLVfw1dbHO4P-Lpw%Ty#@$s*-=2OoGurSu64y_JSN85=fr<)%jN$S zhAsbY{q+0mM+fOqOjo?_^+X;C4(EX_QJB zNH^%-$reGp0PXh|Ymd$#*}YdXR^I|WwDPb+^a|f8^iR?_s*fSOyBI8oHDQ*9gH3L} zJLZ^1m^FchkPbyI+rWkS4Ry+v#vfu#{)FJ@Tc;oDay#jXanNKRi65ceiJMj^;X$DB zO@a>WFlJUiJ)PaHb%yfddb{IS~)><-m&1GjvSjMB3U%!IND{^$jyi*&EzgJ}u;db-K8^>yTb5YcYXm4bV ztzq%w8C2e6r3rapdrxu;b(sB5L2Is+Xmsm0Ma~@##`onPlCF;&4+X%Q8<*g|*v8Z3 zGlm2h9@GIwVJpNL@r{06QCeB=y<+(&p-CV`Reue0;eB z%dcRge-H*Dp#9{5xWUD;H6>t*BKx_=lg!$utPDD=&&}wAK>(aGe zt{Eh~uC0HXJ$#*V)|J(H_rLQ@N^RkI}vWl14mU169 zzC7II%=6lneon{V4YUc6k${Lw6=W3ArJCY0tR^4-ti%6Rmo7k!qr)A-m^H)0z7N;v zDT@3(nh@KJ8EBlY_tJ>-W=>gcZ27BGL-W8gO4Y$Xh{*pLW9@XvdcBn^h zGp=o_HPtcxwUc3LO$=x0J~pmja>s?_QYM5yQq8_`N6c2Ht&{S+v^|p4*6=pdk%cI< zR69?CzRAHe;p0EPeqpbVXeN`kth zx-=atW2wjok}x+AXZt0Z-EeX3Dtt|F;RWPbeGlC{EQ_=eX>;dHLlw7oDf~4|TCl4$925mVgvoSkJ-3ef}X6bbv$tTX5v_ zY31g(*G>4e(sg%!WnymePQTD--)PG7H1VuVCm?%HApzgoJha@|FMl+E^-HfDzfocR zFhTHOq}N#Mx~`jGH2hn3?K8$oTCk~B)n<{iDjgCiky$LWRbx9$cLCS;>&9T1Yi;8D z=?H=kq?xBieKADfz0Qi_HILLfZ7ainZBh7}F?uhq>@?uo7cO*tfsRAttFUiHPNTnk zo_%k2Ja?&$Jfz`JPA=PB=sUpG^iK}$>r|E7GpsF!r1pl=F;g{KZiHET9ACaomw7`< z5BVG-^gpae%2&BK`RvTHf1j7@?Y;~Y3ixq94UvbO_7T(OFTaBhF|9Gg z>^Rlz%R{V!LiF%H;jir?;#F{pGl=kv52;kQ$L2N8dAuweokbAM*?o?ncbcc=3M&Jy zKfW0qwj7>>7O+DvqCK(cBuSO-1`ita4RkuP}mGeCW<*-sH| ztM6r70gf3tjnM{mB+|grhM=-cI!Y2g)HlGMB*M#4UkW=7X3Vldnqb^GTTy@i8mLd(uy*b%s-U6B4tI;ISeN~)um8Z_Gf z&rs9iWhzuw46@*Bs3i4;`9>Zog$L;d>&M_k2UWqd31C8dFJm6YCl3 z{GB(XKH0_n9qYf{{OGKiD?_hc;3Fm}#E$m1Obst+b^ph3bzt0{i{4AV7t3@>I>$M* zvy>oa$(>QElMVCM&=Rh~?|2;*H+6gKv;FU<&@D-MXBR2N+S=@V7wU*^k}+Gk^Y6>P z_ZCk+J5ae;Q@)Bsty@X!8#>#!4J!<;I-A+EV$rw!2J_r4BKl)t&a^mMk#byb*(iAo z15#bY%E2)_!(ZEBrHd8#XwuWBW)3jxgWC>Mr*Ryp<_>s6)N@(ugzZDYVrOdS4#Ft< zPM_!~r)ZuKI*YY)%zgKi`S(s-vDj6%(Ny-ccS6y%?nZIOa0P{RmENP=^rc(4zxgtG znT=gL*`-^PZ@BwX|Ij^0y+3hx#k->F=)u*XfvlN1j`=oe+J_S=!rMGjx55x1&Pi>s zNt3JFpWbhn!`_hB^=X;>L`n&D?&CMD)OE>{0Y_C zS}~kBCjaU*+SjM1)MNs9lE<*MVW+AP5$_@m$#3+AfWnD0{OHI_OVc%?A!G)+9xJTS zjb!8}gT4j_RQ>X=+h zD})i-8T*}CsB~aQFYLJY2x+z)&rT_UciT(2rl}yxA)=vCZB9v`$8FStlxI>Zw7E^e zi>-R?Eki1i5M%9Pxqe?SbkW>4DJ?Nb7Yx`x_FFrEh$D4){^Sb6F>uTpQD}kc?*w0# z>SYl>cl>P7Q;)qqC=zf9Jyw0o2oF1J zac_`kHrjpFCYVUMhe<{tS^W~isiSk?5z{CAi^X8=e=;~EeHv)m=qR8q6;*N<7`)8x zk9j*mrEpj*54(PFWU&IE6XdDS*IRfqfI~VY)-0I$Ku{)k*~VKqCf^$Bd7Zt0wVSK& z)4GH&?>h6>gZ9SSRG-Nb_h4Dt)6WjdUL9&NpP@IM4fhga>ha)nfiv#{oR%mbGVhEa z>KT+w?DXd{63Xh<*+{|s1hWWzOD@2N!rs3eFR!sF&$}KiTf-I1InmCCz>r_YKd0@` z9*8#wv2w6cz7Di@4EkQEBH~u<=-sV<_g1()k>D!tB&eq`Oc93xEW~Bu09&lx_(TmA z#Qun<2N+&$N-iAs?;+tfa#Z{(Z6^P8WqH|%G17XYu4S`AM~5N!OvtUy8qzBp9QMVA zm5+=e{~PS?f7!(Tu1q@0O{_V9q-`FjZzuz^?W` zl7&8+n3iY71YmGa>7C$)h7Cx$Pd_P!@eN*B*IzGXO56zHx>^JaT||9UoA(k<9j78Iz1M~IMvv{#e5fFKkR7nLdpsaP>Cy@ zL0WOMQWcXyhgpPSmf+`h*O8L^Ub?{+ea3t{aglD=defv>)4ZnXBl?GKk9-}AmpQnH z=YN#nXv@brS_(L|kd6$uRhwqS{R&=t%|ky#N)VmFnbh_(tF9WbeD}u5aNE{fgp+a7 zxz|ghQ;JFcJC=!xw?SGbc3m!u^t7DL(-5UFwL!=SJmQ_6-&0B7i}Q6qHG5_m+HHP( z|I|?pNEZ$$rAGO>^d^fqzjH2-26el0x_*4O+|LCtK-SICqH1ZU`@_VT_ufr?b&jfqY5OY5;& zrDHRwZ=dtJsuJK;2PIOPZSznVr`@z$*Y)YHtgR5J4D48|agCijGcGEi$GB*qprA+^ zDQC-8_F23K02e-Z7fP9x37IH%$0g;p)+aMovSK8k*qwdEl#NS%^p0Et#}lzx_8yZ+ zXl1BZWi}XgHP|biS=+}{N|{7j$8IuG{40W6JXUO%daI(f5;I}&n_xhI}fQDWW7eNNn;>1=W0gw5Uy%4WsjEKutOSfu|{7 zyA!QR%o5IyryZ2ELBD<7NMIaZmUp)=A0B$wwb~<32i=|8kWVt`6AiYYy!m`VgrDMS zER46yca13m5Q+Ys{wR%yTz(k{9&}F#R*kBG;c2ul)esI28YXu*TvDNGxe>sT@8($h=ZZs{SM7p|{ZZ7tl+k?vHmk(>UP0SNc8@jD z>$A>A1OdAL`8|r!3!%6b{61mZw-0!5+ZizKgAPpf!GyEUfk)ke8;B!uj3>g78js=n zPMT3KX3G{!x>iMhoL4ok7fGdOj;N#a12lKh?O4?y3dq*DjD|S)Q zbJ5a7e9}e-SEI67cLz6wvXWER&L>5wrd^91@Px@OqqoPaA59!ahwuHSB)}W?{~(!jMc9?f%@;CaKERxA~`GsTzqLU$$(?G9L@J zfEL21sV@3bdc0iAm}9@b6M%o03>!doLWKb-UG(oV#-J@s^D(6Hn%^bjyAQ6{VPaC0 z0UiI2t>HHWIg|J^*jto@63qsoqV{ayQ(yq(u&$e)5&)N#rcW0b;Xzx%@rsJh0z2$H zdQBttBWQe6EQghqOlJ&J4WGWp3icg_8X%tP>{v%vA-zd&BJt7RQ%~cfr|%|p!hjIY zhgWS-AQP{NXNp1oL5K{;5e)}c{3F+U97)#sLR_pFI@?n3YH|H;Vneh_(_n2RKeliZ>+_(Et9FJ!%U!jut;2DP&A`(x)hZwDiDo;@t__96KiQlQQb&|FRavJ9 zY-L{_>ZY+F$Yl|D7x4E#2{Wo00&6#rXpr7M)g{I{%nUEW+`j*x^igv+;lu7D+0o%F z|M%hFhs&ks$sXHX-M#2IyYAbO7`$h*$*+c%g#B&^O1S3hl|d3i^^Y8B`ETqFT*m34 zza>9!4D_$EW9&Cjj;V!&x9MVwhETYc_E#BygY<6H#(bWj$C!G01zohZci*po*D9@Y zplcCg92EUjLQPaybv-=*IMl+%zPr<&NM$DV+!h#Z?qr#o5mQmeaVlI4TlWc_Wj$UN=$P{eNdo!u{VSQKiEGM} z2i`=khm^D}7OtW@KyIfY3aTtnF4vo2{FLWbVEYR%uo_c*pr=I74^ftbrbBeKIyv)0f#e2$x6m651Q*E=SW zx6E?P@`B|HZ9M8f5a}bEjaC;aMwfQ^omUJYRG3hEGr7iSGfK2sD9v9*x7V4ZbmOSVg*b07*l?@I;HhgQa8iMEE4DHvr*FGO{t=v{f#UB zl}#J5ogDQ(#|7MPBhFf@&AzFdZGcn_P~L)bZf};f)P7iwhLY%Q#ctWhwQZk|l_kiD z_!yM1DfesbQ#O$@t5}i_#1NDpbD$@5ie9OX&iS;W)@WJNS=l4-%7&YQdU%=n^*3A_ zSZ6rrKaG?KBSV84HkO6&_d}e_&v`}&WBwG_)WI!$<(O=%ZKo8r{&441gpt$HQP}FY zV?fs`(-$>d%KXWX`_T4=mQ0X@7=N$-E!Un_)bBzFAmHx~LO+x9H%parsIuhk=ed|< zIR9#uA5Fvrb+AP2q&7XDQK)ZSwLr1jj1Hqc?)Jm4hb=ccUSM_~<42;S-+>;zlLnXK z*~~;)etxkD3#BZ57|(9cO9v*dTzO&R~uxCbHN zJyV~t-WHP$pVO7(Ju+qf$FDQIBLBL^x(7QU(;D$5l5lp{^|s<2+V)b8NkmfE>4xn4 zLN9zdXxt#f5$i_SWt?`0z%DAJ2_NZ91#*o^sa)U`-LH1-QUcG1p2BW_DU?x65|4aU zk=?d|$!dLd%2#h1mPPYpo)vY+(7x`mt(vc5G%iUhV-EH)&cz7E4dMh-IwsPG?QmV;TK>7ZprC8sP&+W z6=VqVAc7-?0(ikVIh^&jyrd7d57e6};S^7cW_I*A9*_25Y%;h}Rr(TSrEBnkt3s<9-uSL<>&Njx3J&L)m^d z`|_cG!@-AjG4|~LneZrFSH-kn}(@s?|Sf^Thx0MMcH{O6m%`+8C$b=f<=v{lGX@~ z7;3e#o#)vZCpB0}w;EkB3r&Ew&a*kQ=kHF;*FvFMd@;d)T_#Ur-a9SzuixiIPPmnp zW(tWPQi3Kkd?ZADcTXY*Y(@BdHER!r6xvU*)CB<&wyS!1JGna<-Ac0TlU=9jfbb>b zoI@2Z!r5+)l;NG9d4E4H4I*oGEDrLP_R{anDw5Ivs^xaoaf(0txZy?pO#}?rj)r8c zM%Ka;Nb_c^U|Ywit+FtlS+)?Jl8Je9;~V^z7lBqU`s*j(GXrnrS{X2R=5RU_{z6Pg z)Z4C6zKt_UyMy6Cj^|0794(hq-Hwqw8Tu}m`|@VMYns?t#2uq8_D}rnU%-MDhp5c^oX1lp;VFz!%v)??JWVhs$7jD9j zC?8bvnWJf%%o%I}EQk3M8quYY>d;$dEpkRv+|(F7!}~Ye-%vQ)$ZjTKlpp(QqqdH5 zaXlY?6SGGfM^(Ib=1l<@#{X-09vSe1`*iicYiOWOV*j_nQEW9B*1pTQ6@#rOs+-d& z`*pV5`zYz#52l9bG3@)#-tt15uUWIW4`$k1Ga`t16fV{e%k z*{i)Ugc$|%2?DF?h{B)|x~gaajMdO$=V505H?y?P`JgD7paaLKd->VYik`8|?bjVa6mGa%Afj_E;=NP<#*ROOpelwJ-=umTQE`KU$B;WdnNtEr5j+Dth zeoRL8X`;P}y#fQgYZpBRAW${56|?hJ!u~mIE7u9e8*`$Y^#L1dId@MlS?URDxdkBH z(Z0x6gRR{KS9Bjvf3&y}MyLO9DcOCJzd;IR>ej_p@Wo@^8+#WlKcIZ&>&C-!722}^ zP&sYUzngBPs9C5a44CPUMx4zf(Qlz>NO0p|I1a%5uZh!U==FO4Z|`ee>w==Iv*D^$b2l^A)=v(JL?J2e$gr zoWo89oTXTR?nNh}poa2qO!WR5Qo@?_xs&H1fXKIVRbAi&C*l zLpm>|`S{J7xnl42IdBBj+2_4KPz2gH=l!i21sQ_X8}vswO>RMh%5UReI|obyaEmujKSCGO{o zcojn*9Z&H-E@jZO6S0i3&ZDzl;&7yP{ThrD;LpP8h1irBLItvRaE+d6*2-0*Y6ro5 zw!yE9p5e@4y*kwK-j2ASJjB@pJB3Y&k)($PXS_7+DoY}9ew&Wnr`{m6UhmcyOb=x= zYoBs?dq|_>iv)aPFZiOFKW;ENs=XrjR^O^{U2x=dLi0Hyvv@;n_j)MhXC3o3#pF6S zH@i`RK$ahnA$L%6>BY?+3brt*W-p_=An`H&Se=B^yz#z2{R$W7$l6PZMFLTR^c*$=m4I_LZ@88A@A z`xftFDO8&Ahrnw25AinNIrys?3KoZMk?T`J#r>@l_I3~PW&WsSytCBNg5|eJS z`6Dj!1NS?)@aepVsZL*9($h;t8-0gTq-F1y`CQ;k?J;3M!#xbrTSrxTsQU7FXV@+# z4bwW#n+0_OxMc=mJP2NJ~{#I2f_%nE@~dzZ?NN4R@=YK=Ru+_3xSZs zdzy2+BMLtpjLx94YoWJ6)JBO6_QQc)_{B>Zilh&L-Wkqtr^pqm?j4A&?UWBHn+Gk1 z`}s!t|MuMNa>Iq+*lm;cPa@a$^1$7?vP0Wum)?gl{IT;jeOd*UwoTWp<4*(9n|c$) zB=OrJkiI8Nhug?-!rSS{O1HiSj26ptydb{B4G_bP#MBrVb*a3k$>dYwVw|(FV-h3Z zTDhb<)7biLjaj%^?4SNhEP?~2&0{C7QM>)PA$+H6aq@#Y;&I2>q2%g00w?h``>!#P zz&4fhlC)Fo4@UR#ugMpj7ZSxRSv|P1nEx{+1=&F00@;P>X!Hj&FUT@n~ zI=cQ7%(w~_DgTXhC2`_^Yk@S3w3#|2a;~-pshpyQjoSo_HL5Zd@>iy^IPKgQrr>-vZCkTrphR<`I_=lrmzMN*)~5UUGY z9r-Ojv*ZE!v=6$?LZw58`b^|yOj==PE@C73*N#AmF@1pi^Y7j+8BCnSNX45c`H|T} zxl@(!L&QzJKcF%==)F+%fFm9rnGyk$TJATUy!3CM`7OV&kH7gVWvJO8Bdy7!7g8{v zV9$BMINZ*Y?8{TLJnPjFl69QUukL96T-%=Q%{NVLHfENuN)c!SsO9#Ajz0Vfc)9^T zwS=X>Lg5H;F3$I{KVKvVnfUs`H=vI7*VaoO@~4+$E}MC6J+V`@ysBU7;ND$tP8WWE zKa=Q?t5F*gxUZrR3o0TW|TL0pe`;KgY~{#x=W@`^)YV440Pbv$kSWKAA>`6i58y++3T+SlX=m zBnsRN+Yez7=))s@#5=3X3~oe|{O$Rk?8S)oApLKXbdvIrjUx*3np1GEuksm^3w^MG zHGUtQ&T-{t2?21R^m=`YP1BD^4$n}sHoKqMh^7Vq7n8>!5hJ!pnNDkY^?1)m;iWAp zpJ;=TqBaG%-(5FUZLs}8W@}Q0U8D`M?dSrLj!Sl&>+@BW>gJ)5ot@q+B-`9Hu126@jO!wENXe#^lH zmv1(Z!l5^GGYH|yOI;vDe|g$t6(07ahZlT`$wEF){g)1*uH=QM*jH!|WcOgnoe8boKgi?hdVndeu=1XYcHhwik!H?wV>xE;MCM4WUS#`_ z{>j9O=cALR;1u83YmO8Y;sT8}l493W5G>rp$Yxj&{3zi=pH(I=K{!%OyiCI0q8r=O z3G>!@Tv563aoI?xkCcw{ZQ!aC4V1}v&ZSffJSgGIkI<|qx^g%cEOg=3=>kl(v_!Xw z!q5^VJ*sTfSn>_MPnex~rgk0|_Cb5v9y~fg{E1K%Qc_zn7E;cgddr>Y(9oj8vunNx zs|=^?nEfi#s&3Bcj|(Go5*)Aoni6ts@5lWkS_Qr`kM{4?E1E}V&L3`XxZd`4exbon zaEv)f+v-KMhv`X5UyRqFrK$aJD>11qsn2KhP$ogzVPP;kE*974Qb`tI1th!@%x+qI zW_twA{NUW7CbQ0bO>n@gqD#T10qde7z1AdwQ8r6yBs}cBg^k*4KW66eI{eGNpwQLu z%`>zjeKcf#V9)?mr&iFP?d%8P93f$dn+HT$y&+DA^ngAnZac`GqgQF8?BW~ zaM5SvVt%l6^V1VZD}C%gNSqeONbL;S7AtwLJ2Wy+?MHI$B6e{eWQEq77!O4h)Wb$g z-9O4@9ph{f9(=@Sr0;-M@KRGoX;#LU=~dPNU2ovg?bf(sle0nE;pO4uDZCy%QfQZH zr%Ox`2OiN1HRJ7}`bS1&LMtX^3c{vhPYNz>j_uKawD zv3(k(-__5IEM>ft#|Ys(V@tbVUTD{Qdy{Z$Wabp?HEnDb2U??N56=yAHwt{bUb+)R zj-$BiUU(16SZkNxPtCNT7Pn7SftG{~BvP3E?sKxKefnZMIz{Qd#LUiQg~)4h=FY#!E^m!cuK zVEJ@&CoIT|^##FErs_kpNMz`R2Lli2GusCJx?l2mv}t6JVR+K;%Gn2c;uZ`p9#e## z+SIXPRNaTQ&C}%wWJ}J9Yw)%0bo*sK-qZ=1DJ97#YyR%IDbiCIbuEH= zFn#k|y)4UKhU;cVaMPnp$evJV2;*6(jNWv~;ieH|bSpt&2`+pYXpbe?ua*%1bpHR%WmnA|;AvG)A}}TB6@#`#$$-MddR= zut&n%vX^%Ti*H4$+0>j~e;uV1i40U?v3)-pJ)29SCY$D=rxaPd^6Jo_B9>ur%O zRG3bBGaB5bbvExl%tV%qJVr*#={dDTq-5|pI``=HdPRrqRww}YMq6_4?W(Cp#-(u- zzS6VlJeqUUZD@-}|NL(2lvV!W$Y!qh|E!!kgNsE{E&tEV`sXXh8?=OwpGWjZaz@SB1li+v?U#1qq~_Ce zK}9rtg~yXEKVgqA7?I)f!(B)yK<#`!vH$4li(CWu)P7cJuM8C(zaf{rlZ$^tTHGm{ z_GE|cS?kpOT91J>{VMNBuxR>SiQ&q5(c)!7Vu)ozf@nJKeEi<8SLmKAyrr;ddZp{rJ-i=_48A!zOM@XnS{e$PrTU(&>pv5qYUN z4M4btCuxHO&Ly9ILpLFPkC40NVTIpw`ih~ld1r{`ZqZeLJHatCz@O}n2U&I76Y z>Lp-x?Js>HYT%!`h@Q`1>Gvg?;+fVtrHU$>sC0;y za9B{9!7o$Q6Gf=ICfjP~dt@>Asn=eyk-}RGHzwEs2=v^oghTMEKd2{7=UtlPntBv> zU3W_TSXYOQzADw1Z$-*^(fUeRd0D9)JodRE`y!JY`%L9O9LmWow%@B_d{04#o`;_8 zE0WnFxi_timP1VJ;4t6{>fUunj|k57G`?7(^Eed180f;%afe(e^mV%Xx>*Q@47GK_+mY{T8EG)`S-~C zrBPYgF*j(IA&?>21yv);N*3UW3foX_;{x{IP}CW}jzR1V1FVIm?gPK(Y#>Dan=g z2h~m{myFi4Uq2T08&d_#V!behq}WbR2-4dK?)3G3H+5DUR8<>)5(+^l(NT$|V zm)b{vxFoumlR5Z+8{F2@`nG1WkY%tJm_Mp89&L^$2R0nR6S;xZ zz_!vdCtnn%oPZ#0W?wM~6B^4+-8t`01VCCRVhwh0@nigFAJ(+S`Fn408NUYD2Q~=p z8OxH)O&R0=!lCw=2(xWdJ8)WHb-K`5Qtgq?mZ8SltlVQfq{PeMV>FFRFKWW~dGsOJ zXIoawpt6j6kDrQJ!LZQDK=7^DYM^tL1L!jkt>q5|uTtcoP%xnkiZ1I^xKr6TVY@$~ zeSiJ#m2<)?weCfPCc8=sId`>J~9VEOGZC{T;JL0x{zus<1?r~MzK20}s zA78Fs#iVau2(BX`F|@Ysh}d}0u7!2s2ToDFngiiAb$+5S=;`+|PlnQ7SSomrqv0;S zNUD-ZE&j)nb~eIXm|sWjr$blJNi}k)*xo5&R}*a-*JM)4P}?rgm;i0|wYo8;D1B|l z-3g3JvHkAYQ_pa5GFysmKh(4KAzH;aZhmF;(Y(9YU!#fR|f9>vgwDI z{mpCejK(~)y^-wWSDL`m$%5?&x^#gQY0h=A3DzcG7X@%ND0_c!GM{_A^pas47^h zxNp@Bb!)kd$RYgr<2JQ^E?he_)P0KaR9tvTwkgcn0>jwjF3b(WmC(VDM~iI+l2L`v zJeeee$n!Ai$-O`3tKNo2CPUC=p7&u(EyNm)pN;7neSWH#qI3(NUOwHjJP7#yM-j*} z@nkXxzKObqqZNv7_>;_kcLX%wyHPee9wwbOvc%;&0UymG{lCmNhFUhFxgVkTeF$p= zZLNmmz)sjbgJ`q94&Qjuj+xzy9%AKf@Rq-}tj=-p zmnY?oRRL!xU#T1ZuK0z0F<{&9NvBd4!`6~A5=tnKKKCUZ&W456viSndF@09Fq5XL{E8By+qh=%+VaJLVwP1qX1ulEXmvOK%y?Rq6vfyZT zO~X(P?Tl4AXUoWzHF$>O$-LC|U{U*Gha#}_H$6Y2iBMG?VBQq{#KJ`fw_1%N)s6kY zxhQ(I^({`Sc5bU%|6EpWRy#<&t+T}PEuIYljV0TKEyl|Ix3RSHusnW-QZL*R4-X|=lhG+ETk)+w zu1ip{+9FEKE?;4@?7cVjhub=4nng-sjehP1V;aHp=-)1Ua$f3MlL*1q97okRD&j4|$?m8J>=3&aH1&Ob%1j zYKPk&#TLpu3XT7fB@~6U!g*fe7jjaSFyZyYytZOsINh8ziD7{3msYT2U~~cF#-Q#o&5}U9~aISE&)L4NMGgd)6!lQVvs_`1Y4C;FP&XysilG!~BM8b)>?`ZMKgeQJzCCp+?EH&5UR6f`44yE*&8$!HqKg*Z669 zUuFEqN49zC@}B(yos`_RC?Z-~A;4aEaG(E^dF{eqlvNF>61Jlr7IPk;1BN^*t_*74 z`SUydad1d<*XLDbVJkK|Z`QsQEmBWO0I1E(dQ4Ky+zBk-Qh9gfSFaD_euW*i1kt&( zoKA;hK8T$4m~EzfU6ZzqK{;dt+!Xbfdmj-g-_*|?k{+e_Lhw*d-Xo`^?a^AL)Hap3SqO(ZRd6@` z&dNU*i*Qv?3~pVm0#X!e5Vc=lKLdkh) z%w#ken1)tm8G{|80#mc^9aH&BpV?AH5(d@1Qs}TLsafH(q^C3Q!*9Sj#^+A~w5xtLEOqGZ5s%*+a@Fh`I@%o@FwAbQ3Qu80 zTz~x(go>a;vCfCSp1-=76vMo#wip zl`OX5)JvMFxGefEf*K27Ap3<6hOgr=Mzz27D;qO!z-rg4$lSy$$2)0mxPh0{?)SG1 z5iw_6zSnuQagIKHSE<3cA(ioN2PeRwfnHe^4Y{dRB$+|GdN=+tYy7QLl=G=NtFnGk zi=8h-xwPy>`qC8{OfN`C4)pW|VbaZA;Lg76LSV{vK>+zl2gxOxjaqrQ(vA;fou@6`~&m+h@v+v)5 z$io}Y}g^uY(LKW(x z=0qrR-O8YC%eoNbB4LjAgth5wF)13M-p+(d*A?2XYW8!pWydBHDpyyI`f>M>xX0%@ zn9YR3)ZwZ7{6g4J+zlmvnSQM7?(TBy)~$c*&+RNf^g};HtJPw4b(If(@Pj<}+;hji z|J~pHT^@e;Vfy|4vCp4;@<}F>2`|6=@@=i(@2BG8@^_(I!WIFVo<^6`C3Gu1hal%U zbm{C6mpbUy``jT^KLdO>x^Mnxu<}7|^CeKU!n*eJ26{|UHfS82Ff~GY7c-z2CkeUJtNsJj!wS^(+xa@9IZa zovso-qsxsSf6V(W`!aDm_c>OdbM^V4U34pa1%d7nnseK+HeLW8=)*TY20#25{51rj zJvhW4r_0vnYXl5*i|*zl!rQwEeD{(v)vwv{`ECLt{s21En}h;(fMDX9^~=EaciH~- z$04@fcQpEj^YF%RYx|doAOa7fd7G`XNW2E@qDR9cgfFfubG=^Ii6mlM=(v6l@WT(P zpWjX#>pz8T8@>lU!X6y5>G$bD!lGavDM#mSb5@r>V z=qWW|tby9P7TEQENf-pRV^huMDov?2?DOeFZ7r;>zRw!j8h9wa4L(wt$c0tKmA+Nh z|2~+kYRFcPw}!@Gvk&I#ZnMk{4Srm`S+|f~S*8aCof^C3gN5b2|$`|B>u0MzvJL;|eww zbga!|I5{M)ZQ{Z`iTie3J1G*96(w{kQa49GWynWU5{FVx-v#B%k*Mj!()1oH{$kcb zZ_kTFxcHdkUZc~-at=9NG3Tl{58L<95vx$jQpMMi16j~5uGben=oqE>ec6Xxch?Db7JfGGigeM z>A%+K8-FIz=m&?j{(Nv1<S{p;V2Mz8`Z7MU@qKw{dXMn8^zTOYzssb2 zbiP6;8(q=aK@i#HJ5A{9s>Ln>eqLOK;c}ogVzju3K<0t1;|k4nVifDjNeB8%=$u&~ z;#FOp>3vrc=dXjvE&&`N>;jtg^JC%R^X?m4H9m7tdDK|XJyf5xdOM_VDnaij;B|9< zhlB#TYoDJ*(AEL;9uYlplkkh35&*QYe)01N!akuO5{fwuXkM$$_ozEvzKnIbbm`Ln z>GwH*=_}LicKJ{L)Bluj`?hamb90jyUU-4O@>l)}-|!9Jz;FNdZ}Zh({nY^M?Cfyr z)Tu96e|>#@{{2b$(v&vgDftTFmf?>8R~ZfvAU#JY2ZsnIZJ|U?i$ejV4+Bs9b*=NZ z_iDv6?}k78ympd5bNsfpg22=j1OwlPVANHsk3%+WUp_~&M}&N@5pb$aK*vq1v)_7F z8}&cOaSzT-1Vo?xJ^IP(yGYCzf^J8CyW1je%MNJ$mg~14-;U4CZW2(nxy;1sW+Ow5mN6TtI9`}>@?^A)LuAK`dL`(0apztOLY_S@~jcN*>T{(Zx? z|0&`%r$F=2=l%bO`NB@99N9K3*aeu;;OEJW#aYeI^jLr z;D7f<`EoR>G5P-Ges0~(&#V(@dasnDYR=+vMk=b10rdpjp9sQ|2%c17<7k;}=1tr_is>rh{l24)K(((d%aHRhotU5?_ z(A-y;cRn(UgOp%@kKArUe}R;W*k)Z*@7$8gw5|edW&un*(bCWqp9`h>eW4v5sJ^du zQUa^GCbe7S@svEB8tj8Sn%O|r)Uw0Ml5gbz%BwAkPG85k%Fu6x%G0v5r*2EXI|a0{ zL`&-AdD5q*lCMn4=02(eGP^2rl1ZCwE!QambWCa()KUi@%mm4ER{x&rK(~}y^Kj43 zu@uMCZ4@dLrr#-`ZfRSyS=23OC9-O@WnYkI^TbbcFW$0*3o913KO^rA=hhNwt*!I3 zQ<%+wK34|&lHy!XAh?E{S~_2`bN;9jnD3Ie^&FAyQqeWVVp2{1Py)U(@Yl;ps)BEr(oSbg1oU>iX!_g(c6X_xQx zY}*brGZD&t+UoDH607Hv*3KCMzdm~QKFb6c_4TU8GVUenqsIlSg9A>l!zuw$_h`hB zHkKVBIGs@9skd4G`ABvR*&K|BuyY8tv4^`mJX|0`?lU3XIc;^kZhhl&l+Pd#zKBMH zZcevCz}m|CyoHpD zVxI)KhDMx;fYb#VVOE4JXptDv-n8G3pb_Y+R+q=Eo-XFdX!LrOkf3F&i%(FrtR4f7 zt4nV->fJ@>vV&ber|yRG)`{@jwU0Yk?z`_ke&Q#7V*da8-~WF8@E`ueJo)64{N=y= zm-)$`{7FCq-}HOTOx_NV`}@7Dp+}Gl$w9Y#zg527K6@EGeja+aAl$$FM8L_%0G@(! z2cCWqKK{!JS-%Ec{209NV{qzz_}w8Kd?s$K9`3zs`&dLF^L^mk5kNg4ZZ|I>sOieg z0Rg9;AoBk0qT9}`mXMRy6?WxsuH5U?2HR{fl9|2@EWuOo8zDMSg+!N0m0o}K=v_g99g z7Ga1UMVo|r)gRxksyzUH_qtS?-&_Fe@LMi3Fm#~<@;>%$%EgAL*pp+K)ZKG%32DMfdzo&LWsy9S(l82Bal)t3XD zUqa`|FWK+&==|>6x|`PTJ>XA$HOc_?*U|gjpM&y4@Jmx2imTSH7px7-)`lPC9x6WZ zdb{^=hsxdj%sPRl_e$|B;RX{k%)@+LqLtbSx`p{8)_RvKOl{XInR}h~ODXRx^q7?A zKAEXs%mG#L@Pc_xb}gAlBJU0554qg3#7_%aembT8>^_|BQf&61w*ajcq=J0y7Wtr( zbwFis^sVt*uExYbm&4l{g*DG+f?b`0?5fGi6`whhQ90x)AoWUpRzMybs7%Zg9p!^V zn2e#_CU?4|v*$=au%R05L|{xwB(im2~yV}=&Xin62P}rkgIwg?w&fj zB=fYI_eJX1V>=~sCrcsQEK@t?yHiv8R!o2W2E(lx%YR^%;^JZ`bNhvknZdX0P}f4% z^E8u|N>gMOmQCvaY5)NM07*naRL$Msd8ZJd99J-Hg_0L}bLOOTFdt5}oY%kKQdl|2 zHsQ$XzgX&=EE?x-&HPO!Ewyy>^8vXjgXJ4L6L|H6VI`{LEJIPtGNC9!0_k=S$yKV> zcb4cWEwya&fVo;(=Sl&C%xC}7XF2`w0vmts68ZI!{8|f0_w`i2BU5S56KWxacb#FX z2BrQ2^m_Wg+ZE6qO<*wAz86bUs}%U3Rr(A_90(jA*m>43N!_;W8r;s}4wo-S`20zD z{ykQ?qfweG7pIMFJKR}8+3trhPq^bD#V!FE z5x$rc^cMai8U@W7Kkq;zmQUM$Hf;N+h`7BKG#V%f*~XMmM(#KMchFZ^y?R7QzmNDl z)-4mz$-(HGw%;}yah$R5K4bR|wpF72)f72AvnrS>0=g?5y^ynUTeqJ8Cx41 z$gQGVL}kmqNZk5-j?Mw(72DS(1coOFdQE|^Lm>AJ1k)}NDneJoV*9^D%rW{L-!cJ; zuiLWc2&-or>-)Uy0Wtsd7@AY^WxYM`Lm}jxwN4ts{%7F1&%m$Qa=wo>!dDc+mSC;X zxBi;r3fGU@ckcn7d_{5A6D*$=hofw%sPRl z_e!Z7zq3KdEbv4tnHmoPu&hKkvMH|=|LQsm?>{!y^X&;5Ev2qW5PW3Si}T zYfmK9GPqVIg-m;LA#b;3kk7LQP;?K@x{9#&A_d4ROR4%?G1xBW9QFwlCJ64Hss84bQ5N=0K}bjO`8pL8lX>>=&F8p zmz*=hn={rAW^pdo0@(Rrrt{C#)frTmPGRR(ZB_>ph1(wup)ARhsn#=JSq>|5*VSRI=ZlZ%aZgCJJ3oeppu7!L_^Husoxg@J>uL*jnkREaJV*(;Witi?Sk-J7&$ zpB-A=T}9bcIIa*X+9Naq$@aO!ZkI@niOlNW#=<^xC8opLk_hwOvGzP=>;48Bg?T)t zD?B|$)4e@i(dzx;?eji&@6Q9`ymC0ZjNsvE1Ou-VA?V)6i%5R7K|sGpiMUk{Uw37w z1J0W8c|9OT%x?|-Z(E-^KwPytP3`lC2mtTiv3^X>AhobtQM9dXpChDdEy5?(!Llnx zL3R?)5^8g=n&V1YQN-N?|duLHu4pb3Bdy7YeZJ_4O9e*NAJ<;x6B*Vfj4&v3#! zQQoT3dGg68`I(>j8HU5*F^{bD-2|)Qcz`q2xq5mHVNNuCr!#fa6 zJV3XcJ;J8>dx%hYhD${Sj*|yDY-6`!lj1I0zrG55RTmfw4sH>!6a7FTHW~J%f^4z)`o>?c*^j;~Q1XY4bEx0+U1){1-|5s8BrdEQbb|dB>g&M#- zMBR@xk7^|tI-F6QZahvh7fOfP3QIMuD8g;8SGAN z%5(%ZbRS$Gt#)94Ccx*4g;vrTYFWb>nX0Z%q{TLrtq6}_Fql@=0raemxpFvVK&qAG zqdJ@7o||+E1Em}bx1aaX;*$0^I+Dt_b zDXdd1Nfw>L)RVT}=}l73N)E(n}HxWN5?=@G&0l?C$tQNYEPjs??N z^{=zkrdE=xH65IKQmC9vVVdV)nORmH47#Uwnr}BPw=IDar1g%Jo>QqQ=U}{Bgo3$^ zz8jkw*!yg*RLS;Kw0@oDQ14`&vndfCq}5Dn({=~OBSGk#VSh&T;vS4^ig&Kg6Q3ow zF#x+(s<@7-nn(Ym`^ft`kJ6^Dh5Y82Jg%jzHg1_`N$YL2?M<Z76} z^}Di^C}-rYsd=4dQp?VZGLe>h%qpRtO)J`nwSc1dv^QVz5SE& zWiFWrUG|V>2$0z&G7sD$)RqoBT~+9C3^ZbBA+Yl-5$=D0MtCc>J%?yx!d&cY5p>-n zd`{PF{T>k)H~~Iu|6f2OhT690$$d%$h8Bs0MTcl);!x?V)!AWNxAFI~Eq8=Qnm+n; zsJBRDvv(+Wy0QH(5w7l`=dLbv3DX3DvldcM<6u;xqQNY|1H~`HjV)VTyr>B z6QirsM4}{@^1MNe4nIkZf>#N9hJ9j0=D@B^jIbvtUh%56`+!h!_HCO>#E80iF6|O3 z(TXs0>k&!6Muhc1CKRdHk#&T>OC@wneIlTPMtg3300Hn#@ip&12oSt)b@;sP^KC?o z@~AYG%;uhW$4#JP^OcT5=7P0*;-0l9~1JuW@vi1l-FK+jeq^G|25zBUEekT?1LZtAV2)WKg>V-Xa9`v z|Nid>U^biaQ$O`neA~Bu+m}2G@$cv2mrMQ(q*_pJ5$LSLzuD0;H3DRp381-)ZXquE zJ_o$xo8aizwCq06`D*4_qkL{=+1BUB^~X7MDf(sFoEO?bx1ndyE$0dmgt3T}f4f9b zgNxuFB$Sf}2q3PZ+p^CMtr6}y9wgwmw$j?<%Fd>eafEKIe#>;_>Vt%M-5*;HL0um* zB$7E@vhBH|cf~&U#}2lR_w|-_Wd{LER|J2eQHKfet)ExFoh9=3y@6gO+6Y$qJf#CY zpC>Hr__%u3LGshKENw0P5<0#^1SGE!{bboc3@d$CHi9SG)&@_oR3!3b zCg?f0B`|Q5tbXl+)Gp_W(Rt!4S1nE_3KgH*0dQPF3F@mdk$PQdx0Sr;+BNgoL~2J@ zskRD*OV1kp(y}@=!-^-hDRm5td7m156@*L*+plZEJnxEDi?p&re)CQJKg|Nk07n(| zt49>)yD--N(o%;!86Q_`POX0KCrXmqbXZ9V>h*0{9Hb>FC|PU?uuf|7u$IELWUf@r zokD8Rb|J4;4^IcFF)O1aEy4NJE66tm-|3a40_qzYO{Mj=Kx)S!Xf_pR73aBw{;AH{ z)NX6}=|nS9?Y8U_rZd6V40%vdT(W?rJ;CpklBuUlfm2VMmVkCa>kn}V z`?`Yd`!h{ebPIW&)>(k_aHffhg%VcmR$J&eq+Z7qyp=p+dyT%DRl45BHF+?Wnssn6 zw|^iZC_Em)LO;%Rz%t)~*Xy-&U*}B_OmbdL1~|XcW3)+kKu;%=)=;iioX+AR8sJjYzh>D_VO51b5qq zBNUpyLR?#CtX^KXf-vWEvf&D1zjht?`?3&9WLJZ?h{=Sz7NGRlb`$~ z0KfQ)zsTn1CYzg^eBc8g;Lrd0KTloPy!XBDWpi_r7himlzxr4IDn(K7-~adj{d_x5 zKm9b{`@P@GfBj$o*G#8V9)9>?e*DLOoX>y$^ZcWK^p9?DBYvNib#z&L2srnmKI;QJ zJE4s8M<9e~y@#OU04?_fz{ewFdI9{i&%mYs7`}E%`}iM3<+W=fAl#L%GfaN)2 z{?q}W&!eq1>Ti5;F8=qvbJbznmTv;j10p%q8sR$gJR!pWl=b1;t$vjq2k);B6RJ|5 zW9kv}bT3%{6pin^KJO>gwXYCKwU(`pH(rOIv;OotK8N7tqqhGIYxkOM>(*Gu@YJ=VOOBU;O;IXUbPN zH2q3`W}QIOd!ZHKx@L6b1QUEcIaXh1HdVV9JmjYR^>bF4Qx%<1B}d zWwOs(i9DW=cDBv0QvfrMDma))W!NqS9oJ5gHjYBcStcoDivo598Pi%@3dVz(094y5 z>p;^X+RzB!EYIPlD^gRZ5ah~PO1yRn)l6aS21)ZQ+d$pmn?qm+W1V6i3ZD;-NOc8E z%g6h?wmxa6P{(@McAaB-%fa=`)Rkr>pzP?#Nnx7d$lzYLAXCdX(;#&oW@uG#^$jJp znr2NE4yw6wGv69hA5KYY9i0Oi^>4d~ftV*?a^ z+kkNmOQN~Sfx6o~0C`d?B;E%MwoaZ|#`sw#k9AkhN3{-DkpxTqcskH-o-4H-^Kl(8 zJZH#>JerV}`p{b;RTT^dFr5hUn%x9bC1=Xx+OCb35>^?IPo)x-F|Nr6)qE16zB#5i z(>2AB>g(4@T5ipubn133K^3wW@Ij~9HZZBlhZT7|B2R0Ivt6At{Zi-rQLSTICRu3| zmHMjy`gW}LW?B~HBYPJlYDnqJpftT(2HGd(OH=%wxr#;-V**%0q-}K&S`n~qWS?~r zJaX0K0^!N&v3VXw-Bb;3*miyY9Rir`qLIWK2$FeS4s2fzfzA^E)8FL#Ru>0)6}o0e zwr&ThB7MD??aM>AUFLF~@TfdZNK_UPbaKU>w=ol=MIUAM5cqQ6$xMW%XY_npwR(6x zJ$7+Iz(R+h%f!gsM*Kb5pUCXK#&IuOA7Q>`%R0oHH0tXRbHH&p zJtH7!vi^F57_IMH-yIS1s5K(|%tz0z0(H0t;i2j<)JMH-JDv^?2Smt!K_nmZn9>e9 z=Uh4L>e6*I0^PE0x)R#|UPfxx&l3Q7AB}R?h*9k8_It_t(gE&1VR7KfSEnR>>x&x* zG$*U0_p6UI7wz*7;REcG89i%*$A>yNuZVNYm8MQICfq&olJ@{K{gZ$4PagaKKmX7F za{xZ@fe-NOzy9ky`Q(%Q_>ccMfA8=8Jq`{IIDPsw-~7$r%n$$Y5A)b#j~!e0@BZDt z%U}2le}TXF7ylx=ySqH~)KmPcfAz0;*Sp?zdmHiltSllJG(bRYlSsVe5X>KAoA&uS zk(GWMUAoHvJ=i?dEo2M$2!c=bp#a%S=yu_ALQmQ~tsd%-wEb<` zzF$X=yIpHfjX>O|8~gbNTjxPr?n^xOK4ZHjvDR$2%(alSl^r_EUwQHB7SV0 zH6ql1$J(`MpRe2J8wfNmTHQa|=;!su{%hd9L`eLL_VXa&7F1iiHj%P&(Y|*T>!#JM zZS{1e=Ctv1iFkxRh3549G5-dF)*dSV%>*P}u?f&>Pv_64t&jYX)+5xn+g6`l>(i$R z7oR=b?=#j!pn4vd#w1o^X=ZpZ7N^M z&#V(@dasmrF;6BlS2lJFWoDmNusb4GS;?XLHX?8sm9zX5r>RYNnNzl#>$yM+OzS+9j>D$cF|)7fY!amzNase%gR&+tjY6_*4k{ zOpvXXI??@EDH3V9BdY)pWzVM89M`1PwnFwtv&cH{@X`_!;U1o@HZ27T=ZaOkG3D_T z_I3@%5{gn+lhy_qn@~CnGN&?;dxgGp`0J|INj7C|3XnRnZCjXnT4|H(nc(W+$lhoY zsV=Cur?5XYKwQ|MrBSCkLCU65wEa3L_TnnkWt}^oa3^Ow2c{!9oXz_ybqh=OL&7_%4cdfMzXjX!!4r&uR zwl#22k&g~ZXIGVIX)-2TU#A55=7jop_qg@ReO4dr(EiQ~0;Nl39A^i$or1L5ngj3R z;)1EFYn_K39lz9WLDz_3uLnh;Q)k-}qWL)i>I3&ZJ*u>=!Nf3l9+qxBU3HoTnn7u)|0nIXN6nM69I) zbnjc=$5Ep{XI8IMgd)~s3GX8S{kARNX>7lP0HP}+ePEJ^b8u?=d@t|^fSc{I?o}GLN(3MtSo@a=gFJ{) zdS$;IroV{>uRX#p;s!d;efz%dvej$X_R+i+eNuM8_Tkqp);_nfs1Vq7S<{^^_W(5g zzseN+gFpC#{NNA%;J?$h78Vxx(I5R$e)LCw^h;5-lk#sVeFS|#m(eD=ZM=u$;m8}r zBgTU!9zih81?)@(*sj|$KLUIVU4E`cb!d4NsHdxxqk z!v}%2Eh1C72Sa?q{&sun?*RU^eYb^f2Un~PYqqTlfkamxy226L&Z^bVA()HjJqW`4 zbIm@#X3Myubr-2dFIb(vn*f0$1V(*s>`z<$YNVX>xmP`@ zHu*f;!1m#G0-ILXHLLHs?dNHGPs+6(70=dC?&&t}=f(4c;?vI;e*|2#eeDAO)pr3u z0elS{U5ABlfp5KnPQLSye+2%i)wMvcK^s=D1K>9ic&!iw_jAPO7N19u^N+8%k1Q)%g?X+!_({=vUChfWz9_j@`Qn*xpp@-fmIm zm%V(2D^0(WpIIl+^j;~wB0yW2NDDowD{qbjrdC=~tU2h+2p}c|>N*7})e)LLl1gq4 zQC&d^c`bVs4%ds8V($2ClADMe59p*@>JLl#Stdx}oAjnwbUP-Qlw{``P^Yf3ub zBb{msR2dx2vq`9ArZpT^f=UiHt!`gvXWeJ$f5?rw2_^ms$W-8R89?_L5YT?F1bu zhwH7eAmlwd2>YGKZxVx0C$#28(l7cdXG1M>3~1_^g6}EeSyp> zlXs_KS>d7Zu8J;njir^=JY#)o>Gqk26H>1QRYl(3g@c*kYf7XAhx}=-ww+HbSXb0n zhNR6d=}dQSi{Xi{NJ&1#SbrW>(6)2n&?Yn%?)+{1BoWj}`J#*a8n)1z{f_^j=!nSnFe9=ttP$b)u8iGnwAn+TT~WDZ`&=bPiVgzZf3zlm zr9<2qk?PphhM5R`_fd)i;--qz@5N1Mxk!ZQ`)GNako|1gzV`@a;bx-`X>1=N{JcYC z_i!-h@VQ68?|s4_)A#WJk>F~E0QYNzO49+cLqQKUU$brQqT}VZ1-BaQ-nTyT5#P(U z-)-A|7o8^+I(HsI(xEj3B44x5SFC>@uxa=TZc!Wsq zl?dQ`hEV2atJ5BFj(B+;T^kqe|C`poOGF~FMFNETyW=UVx4jb0pOLNz9}yM+m#hzN z+5f)G-B9iUXnIn<^2#gd6263>kB7Q90n!v*-VW3r0yYZ0cBifY)JK8!y?9&|wryA3 z?Vwx9r)@ib0a$quUU*e1R99pA<>+DKm#tn7Pa(wgu6n(Mfamk*@?N%mtP!`Zl1TdW zOZMHRM*Sc{svjkSG~Q+P^7R)91?Rf`UTgH{)Y^T?mUUR#>=y^4uB3JMlQnC{Lso}p ztPftXeYv~LW#W~hK#z_N0?z(8bqMWk8#Vs-`OG(noQd9--)?pHc}ItW|H9Ut+K$(V z1XiWht7qFhOXOL6fdJtC+TuX~*M0`hJrCEe>+=U5vqtQyk?GIEQ$MCQzKjwt9Uy3W z3HVd!w!ej7@;P*#?hs(T^oD*AcsD%pJ?g(LtKF?#e|1%8zX^ch$? zUqs;cown>{q)7Go-KP)(_T%A?w|l01g+tS?KyP01Yl1s%a3tyDp==AlA{V%DkagtPc~l=)#d?@_Mt+s8B=6MGNU*mo^x3E; z?@UN%yK_Y>g&8vKm?X;vo9M;ES zwTFRcqyqKrBuph*2x9uaEF*g=6S<4R_5DS>Rml6ZNCKxzEx|$ar;JVd{qm| z6;e{>+Ul4y%%89`1eXB zd4f2{=PGKe_l&TT$ksP0&3$b1Xa<9Q^6pIjs;xLj>6i+<5adm*L~a!@t989iYt>;| z&pmomr-0Hb(=7zB*V{I6FoRX2B~4I&2TN)wlyB!gPRc!0Y6MYAB7xCE2pYagr~^G* zIT2yrH*B4oXyj9(Yt7@udW5=igho-<(0zWL08BozfPkopZh;`an-(@##0^DXomgGK|2SoV$iuI){8An8Tw)=J_Lhb4vtF9d8Ez81j zIP6fnCe*1599I}0*uM9PtnV!}65Awf7+k5jj-cMe>gEbsKaYIW>7(yt$Lj?&%5#~` z!1n8^))}ENzKBNRP7zKK=U59t&0PXqyU*)lV>^lPS6yn<%YU$CTxPRPTnCwu;rKap z4vjXi5J{7nR;84n20&}A%fP9Js-p&08ny9+El2p6XCp{u$zY@^5MQ$$$)F1n?yw1FpJ?bVq3 z=@T%~A=Zev1-K&8;pzb0HXcHcuivu$^pHYylL({VC2p@Cg8#fN`)w$x)T_Y9iCg>B z>gp+698?|h74=i#vZRE@s$+tniB#8RVIg55^{EfyIcZ=d(!CIXI6wqbiJ$oFxy|Et8~@Vxc+W}`oQM40@6ZTlht z!rd0Y`)g=F|0}TjBK)sQaCFFAy7{?Rwax=W?fX3PsJ)25<@45-w*%)2c&KKcIO#TJ;HaN`J{*y^rxx1X5=a}>0&lHC8SgtS zQ|whrJd+Tt>K0P@^~=cM-UL4&m^v9lQIghsiqqJKD;P+!yCIM4FSNyv| ze!1n>tn%dd-wz8V#UqOfe;*s<_atUZtqA{zuySZ8T`QJ+D_4_HYme3D)Uo!JNy^(< zo?B6n5iq?uVeenO2^m)Z{rg~}D|p*BP+lWjjGU$1wx*?n3YOY%YogviY1XzhQmov1}fuT@c`KWXn1ng&0Nd6MmD;aBc^q8G*5aP}O?7JY;{- zK0njw*RzDI#{0tCy@cT5$m)I{5wE(Byga*TB)CU_V^1{ICc^87Xav^`9e35J!^RE) zAN{8y;H>xe8yr_tHbJsOONX?ssQnz0=D4SJy4um()0rf1U7gtq4OxCl5Y)?>E}MWp!CVlM<_h<-syifEP$IHsrW{ zfrE5cD<>kUnV&xnxgoBjJ6%qo=}EZ*WsUHT+(MV{CIVx-woDJ*PS4xl*MRn+F6WIt zTr(o}@mKZTbHr`-d2}m0Pb6F_fPXfHbHAuZ=oS0!QQ|S{^Cai24*n>)fMD68ZQDWO zHkxx;vvw3#{|*sQ;O!g{Hq4IzKaCz)Z%2NeuUH$W==R{ZYFC;1W9cgKc=C|*9U@e} zV|DR$vF-ZfdAHHu%cw6rto-W;h3XTw-5ugp!&Q`P2>1>VRP_2iumrabWsk6qyjfqd zHa}{0SZ(aPwz~e!Y1mqiZC_6i0X4pFhu6-`9Mt;b?-|1CVT%BYSUYP37rz1cl|$A2 z@gIZ#xz@hE1K>UIo=<37kN;74$JfK#{|EU0+BW_MaJJUD>b35|qW-k)%iFta_1OnKU!Csz z`@p?YPL!s1teim8d!(dJmpmDh560v}fhLw(0#gYkLz-p*!3-3;$6_S_l(#0ZP?OFqL3@F;kf1mqPig@_5^1Fa?HT#-aIUhWWe_fB!M|Qf9#^DJ zJqLVwe<;Q5LJ_{HROWx$62MCdrjWXADIa?!d7_xXJTdrqR8wC&k}A)^Vr6Y<3k}{&$(wxC|ui%`G4l|SW35y)@=&_dPeU&tLIQKbqgsHivngdt>eC>qZ(QU2d4&u z%a)QrzK&mW4sm@h{)A z9_RD4mjCTiE7a7T1f4``wRB#M4c?<=6*kXYDGQKyH5$wgM^g&5YDU2I&_M4}i*rjZDc*TX?R1+3_prT#}+qpC=b$k;-oD9;=|Cd|%S*3K1M?@e@n_4OR``AF33+#{?8 zwyb^2RtFzNd3>OUMZ5H5WcBpW?rlO9*dwe2T;}15*Fyq~E)gk;J&D&6f_tAqgBDjy zV%u;V0l$`KXyo%6@D604HbV;HBQ#3dLooFW0oxqFU9oyEpyPTT0mC-3PZ$s|*hiYL z+jh=a+hx+J=&|D-jxP}2o$ms^c@-GK zb5nhO1>IgYhf@1hHT?h3rS0<|E_&ZWK=O|PzeptaaV6q|M8c$tL@2w@zj!^LAVA@c zeRj#VacUJF-4mdFp0N6Mb!87-^370k7u^rhRMQTvgAXyO;cE=PN8~%>gaXwuyD&Fo-=AwtCW9b zCkb4c`Y+FFlAp!hg0$E&m{!TxbX3WMb){v1Fh#hyCpTKOz9~=}6A{Xuvy`B-NOCl{ zH7HA{YlZEnMCx}etlyyYWUTG96KSbK-X6^pDCOZ)KAoLJnoa^<7Ld26q}437XuD0m zH6ULf%k#38tlx@I2Yc79cjPU4eIPH?X)PePRL<44N^~WNDFte>KF{)it(XJ!Jg%XZ zk})l{r2g~)WF?TDZ_P*+;y(93?G@yGgQ)$Mj-z?x=CRtDmRscEjC^fueyOG!&b30` z&C(zbYpH0*H7Q%acap&NxQ4x1BsQDWb1%@;Ed=om#wM$G9te`>k!7Vf#cf)&^TW<@ zrWLtu06AfAOBMOBqByez>l;c8b~J=`hqTcm569s47Rk;fS7^`T`bwu-q~&sM%a9hk zWX7aAlan2%Ua5MOr2x7O?$UZEl*9c(lNdK9-0|WG#%}jMPRhMg)`-wJtDU7 zvVGjrFYjnL*egw05W*tK;I5L9y|G>+6aA-$Lh7o3O7aY=8IJK9j9~9UUV-zOMB3i2;{F4Tw0}TUM7vA~{t_ z9LGCdPN3;YxdWv{m!Z#5>=2O8q2~^e_jC&=h)Ze}NJ~&1MyR+$%`J3kJFKj2JL?FP zT|~FjUnEqLYlI5)0Nn;QiA#2_{9M<@t^!ZLn|WrX1U&sBZ0+fBzVQ_uc>ukGU# zNSWyKENukDybV1BF&&6rwRY`u+`7OYWt&96i1*_Py2b2Re_gO`yA{EfE&p{yuE%SL z5jrsb6{3Ir5$eas>$Q$T>HqO3!peIY-Hso#?@Hij2^B2rw)w62DQkig0RM#b#p{iAc8TDPRom{XggUpf|1Uy#eD{I>4kkYv5cbJG0k8b? z2vQj#CGCf8+us2E$pW@()$8L37CUg>MaON8uxfZWF&BNwKKo6=S7<33OE{)UmHqIhwndySEd8s3i8ermTJ;Q$CM12Tusf-w5_^~1*h`CRN>gG9q39G zn2${5H_HZmGikLgg=ELnlSg(J@+3eGx{8uiW^!#%F&PBTf_WYao+pBzsh6ZM^+9*9 zfOZ>}XM%VWQ!IKY_N)#CXulL#T`1=&)_D>kSE9Cvghd76tJ*0A-bS@71qKL6E|$@5 z_Y-w>XQz;*LJ#vrZ3zUA1WcJ(hYQ#bmOpeYJZQ3(BO(tu+_xdypIMvT=^p$2du8Z+$U13b`XR*MX2o@+_{qTG=fB* zM{npJ!QkhnZx1v=@%{7&RpyY$g5crm6#@UwAkgKCJqOF~8|g7>ucFc55s^jSLGX3k z?%N0u>!VBuSKgl;``ZCoO@w{#S=~<&P_bzAQQ6q`p4EF`%PtWyhrS;N+CIHx1l~_WtG@&61;Rtt`|CWBN#>j_ zzko*Ue(pSp&gD-Ls%M)YpG$yjetB*K03qjDBP;?O(EByu>oo^-CAt>eW@4KF&v&|< zK+}_Qhsx{3Jky9!*LfKM{{TVGhwQU`1iKyp%2nv?>9)0xK%@IbmbUHZ(A?2OM6xLl z$9E;@CNVELA#PKCi+0#L*^!d4=aqA6xTuYO^Cz^wy0IOv#}?rZ@=+92FtF{rN^(Fb zLBGf9xnn;*x8{!=2=L~8=C`g2K{to5=Llu*Q&w#V;rwMZ-*%Po1-(MNiuhd5!1~M| zXAW%Fh}-Rhgb(Z|kebs&>lcYf%vp5%T|?^1k_a^MN2SBs(&~5#og=T>zB=fU`-rW3 z+4{Oi%nPnJ>br%`18=iK$ET2Dc3}xo*Iz>S>R(bnty|x`^3PRYZ@Uj~M|O;U33#xU zMZv}p+O^J|q4m>?L?W<`eRj?W^wVo_ZAakx9mKrhM{V1efOCHocpYAOR_#Bq<2WIL zhhDNaE)$ap4)O1);spP8?@YaATvYKM^-IbCQX-(zNFynz)X<&M-3>!`cc^rOfJk@G z&@J5!BPAU}4L!u2bDndbd*AH$vp;+Ov3_fP*H)pw*ndwYa<~kQdWEr=GkQu?@w*=} z%VxhhTVsV{qt0mI1gF!kzf;g$(#RBuE>9GwS&!xvOJYG_wfhs;^y$2&}A zx1#;@L8xM9EeNVbUAN&_dhu;s2j8z`{0qUnAe;$hP;$jI?&TRHE8M|kSX$2e8gv~@ z-qqgsZ<%y--OUKrmMS597!%PgB&ZEp~h>7Sd{wteD$vM3Pc#@~l5HfW$AHee4Y_SVz!cKs0&kSicZ^AJyB(_iPP2z;rtz;c4l0YeUr-}e(Z@)% zvMOHQhRe+8L>_D4NGLyn$9sPZq8sgDK{NXl@@%hlgP6{KYOAcCd@t&qHpJ{=b2LX0 z?`I%$@eR{nKPvkC@)0j#a+mI1mBXvDDC=-Y1)`$WdM|N)l-MK|dtF&uZ$WbR5^D-s zMf>LNln7@g7c?86Q(?`dwb%)2km`2D+6_GJs38UHA9lOWFLX%#WGcblsqfom5kvp0 z+})FxCzDzGx%=AXJHX59sz#xoA_*8SJq9^O;1j_QUX^*!mn}2-e+{6nUZK#VerRpF zq6Bw5N+ZayIp-7=DgM$=Bx~}{w8u@TpCT5qYv$P9jq;kVe=_oTG}jz;Qj&ju-M`S$ ze~yio9@FwDp@c-KB+x-a+EkK|z(b6z+!R4o3Q0o-$35VrHu2jTkvQ>K8A%#(@+FZU zqf39D$-%HAN%34Ij2&R8NoK{RKfV>&ZJbx{!s$Lj8=F9r;Ce}tctJ!HxBAg%>f_1k zKG5s!Qsf2qlK)poDka^L85;cfngDg(68ezQbo2Z1`q~&ha0VDO=LzS4?tDVC#pj^} z_~ya%+9p;ms?|LH?DJU&u7U#}YnzZ3a5xT;a+hrLf;WvsUdBd!f+qZ`VO6X#|^opdfwl1OEnM%H`s20<@8=9&-DK zQka7pjia56}lx$rkVS^iKzF+FS?tzHT9;bI)y zwu932+$i3Ww#aEh-nmgYWVMWDSq)dfv(1>bX{;3I3~y8BXhceTZ~^0za(?^B994D- zX?H=XR__m9BS||UIedH(>Z>$4`F{1QdM2`vhsFG>c#&<|Ug+ZuqMk6D0)=I?6vZfjLihOA5`kO=!4jrEI*Vv_h|Cy#?_A(WNU(6gRv8W)R z+f_OIC=+e!ImVVVbs4)Y+8`=qykCv0OMRcBlaC?iNW21bHfCb4$gEXM=JJ@ua#Wjsa0-)ackR3w?#(p~?j~?J>|8Yi39s3DpIjx2_)~&A=udgT$3i zt9Zm!oq{)}-k}L`&@R!4Cm9a!iXeXz-nQJq#y}Cr+YY&!d?Kl+1e;3pOniVUSbWGB z*&ew~e0lvi55T9&pYHvE(v}DI^;;Ek_nTeWu(FC7dedbFbG6Lv9TLGm~H0LqAcN z0HsBDScvGl;wDCgCD9h5c)eWr9u%pd)~bCC%t7^wS&r;IWvphJsCtHI=tT#_d9 zN9{5{nSd^vge2kuJFg&ZMSn5lCzCG_6)Av~$DfZuiCZTu0q#CQxUF+*pf16izAk^t zTp@zWUTS~LT&gIUT}?Dma7Yk!^O?*>dJuQJI%O*eRRpvBLeK??$T6IWC#Jc_R)*r&7BTFMHp>dtl*? zEB`~M>^4`s+0|_nb;yl>zrRvYv`_RC)3fc^osV;r2tKV*NE-I&Ev{J?&xw*i7)lnVs7oYHA{xkWY<5eudtxK1q7ulLre>oz{x)}J~tfR`|3bzSm?N=y9 znRWuHg4kMto`+8P*vCeC5XS|$>lR=#0$oXoD_H3TB)5MYx8{kzOkRl)A2EEZ|CR>U z=&+I6=hkFiki?oCz-q;MoB7Scbcw}ZJ>*zkg;1?nqZN>Juo9Ns(6==&wecnQ2Hs@qtkIw!|tasdXU{t za0!0oAm828z5U(9`hZGGG1Ja>4yyXj@DqC{!l?n%-%(nSXu<&PC4OEZ$*^Pu;H`ub z^Y(zOCrV=FAW0bKtMb`65R&tqeUSt@Wo;EXUVbLXpN8u4nhDVT=tsJB=YfecS7@}j z0*$BD#N6I~*Q+ck{rgJ#YdZo|FMv(gUVvLK(Qq5>YcE@n4&xfC9o=Y0Jj$fby0EC| zBr58Q$(84|;lw8xe7`(r1a~;C_^$04;n;6gUmfwB=~hfq<^S!75WTks z84F4l69hSu#exF$Xaby{?+=UT z3Fs1+>gSL65dN494ZaZ>I;CIhE3}Df|EwSpuj^|@TR}|xG0BpuOglFoE%MtMeiW-b zCE?j)0yJ{?dsk?6?(g0F-o64Z5rP*qmp#pNVFP)3RF*?3klk>7`t8s zy=A${t#AD)m40C9j_@Wyg({gDS=V9}2rn%$Y-h)##rII(Wu*Kf1F)fXY2r;w|Agc+ zRsIafou!Vq4=)&A@^m3t9cbrVi%3F2!UL^{I>afKTwOa|3+fCB31up4Fv-cO07a|Ig#&p zvoy*`2@Jsw-K%~ysP`2zhw0H%wV|5|J0VRXY{ZGHZCqRPBnHGM9y&x zeIH6QO_M7jO$i58u`^UR37?Wn=4u@#yWk-w=|}7PV;u&oWS_1SAN@5XL?T*m@zeeX zJcWl3r%P~RZE+MeOWy{zs<}uqFBeN@xXFb_3NmLC9k!|iKJeRkXzu^2GralME_Q2Z zRBLG@=JbRB$KqJ>tt0V*w6E~**3-!m%MI66MDp`#0iDrv)iRRbw!P?VBPB*O-3h*k z){ZXTOe?|}7UzTQB^8auGWtM-b&;d}`vaQA_TfZXY~CO9g^r1HYdPRwXryfgwYuE; zne9`#Br7VZ@YTpb9aI9;j<0BZB!{fpgF1vAAzXEzzPyYI-l}%=SXLigaJwq5Fd+lI z6`8aO-|73^^qdf!##b->CZ9;Zo;s@eGq%*8W-mPDbL~o1SKzV8k?xJNJ?o`m7=1{*HOG5Is6W*+vriM*I z3ZMh)nUTKdGp_CaQiGLW{_&?bK})5SI21zD~H9 zMbs-XI~a@o@*cc~^Bl&L9lvSETCHDjXd!BaoxGAa6meWUZtJ8>4(cc=)Zs*r*J<~U zI-~d4Z;5ma9ZdOCGWB%7|f6Y%A2wrix@{XsAV@`*(`Bjo1@!WWxR zf)3Demw3HJoj<*AykFGpGg@$<#!r0oa8MK~emvi(p;B4)g)XeQF}uu#?YBRrb`=F0 zyuY9_5*xfH>J7}t`+0{Ry-gLa89K>eEakSW9c+xUc23n%oNdW&O`cb7GJ-=E}G&fO?J%V#lGrW4T z-emRz+g!)u*Wd54eDE!f-j$MogKSK1M~h76Oh^*|5y5Q4K6IM8rfa#Wo!T}*M#fkj zvsng!6?sFJCiCm#U8zt<1*%_uA3FpIthnshcw3*-Aihz}hDLX}^AGk>g{~!I6_3 zcIF>U2>AskBp2R81A9yhwSHDj4#?XLWhqos!qN8H|APGd`723A3gKL0S#Jv!hhCt{ zN}(1_>;}tpa?6#lf5`|EZ8!WDd)*nr>p>gn9$QShb= z#OUEVoW3{@oqd2#F1F?WSE|MO#&%h|j^4Yw?6msyWrgx zr@02(WMMkTqS=AK1(4v{0#J=1_nz@KOq;gr&Exh0hU3wrDdLzG>S&5MB_f?2M*&0y z@g?%w%?Bdhzx6kKdgm?Dhq5t!k2wmobI|D${sn*e>~BbrbOu%e ztZPNz88{)|)+~B&!~iYJev>^hB>{xvX0Z?tL(y>lDBg_I9;5cse0T39MUaJK_(=mH#9**p0~`k4Bke>@#`SE!GG@#&;AG_ z5Js#_^0R_kNdJ$pnp%m}S~fF%tE`%-@_65+31hT%xo`*bu6YB=U1^e?i$N6K?_{$U zt$Hzw+=^E`AH$UJKc?6Ud*F&yW`4?bQY!kX|9X3vlI5ZFrJ3)pb3E;ktg!B|zWQP8 zH{P@)&Z0`stj~KC81Zg`CD7oUIziAx>s$d_Fq93MM`z5fKbYJ8yq1~V%#vnEE zdvF80&s;IumwCs=(YQfyO6t#guG^ing7G$W22a*+vTx?uCBeco}$_sc9^&^8nl& zgfB1qRiCb(BdhjIrf*zCOPL5_98T0L_V{{h&P{oLuSjo9hx~ozt1nXT@k;GST%}R< zkDr8AcKD_EF<%?~yibTalQU&y-6PME$zQ!^rOs)kgTGW0Y&8rPS+uWs-m+=*2)B^K zR9mv*ZCz#B*f;`Dc7i_U6PcJk3%&#`3*fUEeqCvLY-XL4dE$E~9E+`!1;9LTH75^< zV@vdkN$ID$(IKX3W~9l94>vSCq`icOkIW0(O)gzK64k$3U%(WX-;!4rvG%v%uf6&^ zvFR24lG+{vJIKLcrAPB2@2lbtc8?=Tk-DL+%0!1X>&y$3{xdmeF zx1M?U^Oz#FWXa!6xv<$uO#p5fH)=NJf_U(0QX3O$N;-0jQ#%n|mQ3FW+rRcmmF;d+ z@(#XdxOthF8GvgzW2k@nJK&lXHAah?OcR zV9?iry6g;_?MIJS?hy;mI>OJ@RiCByqS?Z7ismsyZ|)R=3K8+^_cD_ISfYAKy7O*X zZ;69KMQ(_LQjvr)U*jN9dWMd_c#iWKtxnwwBfqbMi`2ty3ry(x?dV)_g?2X@=lK8K zoQzffyN0-G4u8J9dOx#FRoN&T^|7bKR%@xbLb~LIm(Z9%LBdTP%VRNVy@8w1mVZv> zvpRYE!R{@PK}Qw`E>b=O!Qg^7CHAhL9x0HlILUd$fE;a{J?NS!VUl*)WX#NL0il06 z3iS*cYlCp-l`B9!+Beo!n4a*&Um9zlcMjFC{nRg>H1cmL-wVTLUTHNIa)Iar1a`ab z24u^Z6uztNg{TF@MZ5?izKsoxYKXZMdb{?jotdca}sZ85=sqId)98PQ7I3LTma7gPrIff`kV#RKCVjliTT~0Rs%aV z6BW`I{EJz^L*PfcgP)XI#ai{@nlM2XVwGOF$_SZZ>wc^!c1NOM@Wm2@O;V?k?KJDv zPc}fm@Hc6T8X{eQ0ny4!Ob(DSG(2>+LyEF>Ri^M`H2|;;EbpvB4nSN)Ch&=PPMyib z2h{ZR{T2q&kDbypEW~s6Gsgm+tMLu%KY<7dZzAWPKhRDu*98hHFmu+tnn{?sK20J9 z3>|czgw7w7vj>U1Lw2BkiC$~yboMBbIJST;*ZPh*8zYbV47E3;t3pr!-fm4A8W&u!uhGG{X3|Hz=8&}$D1 z5l5^#bC2cvNm2)6MEG!C#TUaE92X$+I)Afl9T1o2$N4)ECiR-ERW8^=Tb)|xnZQ9G ze~7aGo*!Tet(AH6ibE%;Ls@j%P~2+14%}k4VCh_Kac%#5eDx!ZU@t`w!2-xS|hx8btJ+vgOqth2NWB4tDpM~<({KLF8 zd@^nud4+=XJd|TdBHg2=RHUc?0IJAHg@hpMwE4XoO3#jCp0<7 zY3=w#d*Y+-7?qJ+0m@Nwhh9RP+x843^Y?%0*RJb%fmQ=5p5b7J2&$Y^WCPe|uv=%{ zDpt(YLq&gq`#2c(O(Qy73F)C;V}vNL*H3C6pCVg0s*^fwx@z}yRt{$Pe)1{u)FSDArfwa)z`vnb?r48f5*M;M84BSaIMK4U7dPkV}4t{7wI4x?ugO~<$+XPlGmt;h9p9xX=mkXBIyZEvW_YDI|ivgWj=mM z0*UD{VaF6R_GMcJ-rEJAIsC~RlI zC$%-=zC2Yno9K0ta#cc!`h|&&vqrZ-wwDvITyC@|LJTKvw-09w>oa>g+0$b8Jomvu>!|ax~$!<~dtQJzv zNKC8RN&bx3O|7t5I3TeF1;dI$x#b@|-9xjAg`AohQ4-&l_&w)%DH+b^)HBpvZi5ImfSbX5b zCgzS;aww-0`A^^*+#a>&<#5N2c)sI2!(mDE~G)T+oqr|Z>iATMeK7QWw~E-do<5`KmXEu=Avo{m6`>Q^Dv!{E?>EP* z>itWFg^(gFqRUEUto<~X2w8#f$7hc1uPxSBp48L!3oo=Y1qcnmlR-DW%>hC-P~SM& znQ+*Rj7YI>+sHhvp6Tc{k!WS`fy`y}g-`dVGg!A5uyWw(b62MI&VBX}LK z#0OQZ<7hUc?NTOp5@L4r;kV3PMJWezLPJM}ozZL$?Xnr%!L;Av`$w{M^i{22ckn(hx`K+O!>p<)zfcenM)tODdN%2yhG`qzi+}BkB1bm zq#0*Wl`9`CtY4@C@=UU^)op`Q$%#0t>LNN;?Z;bklTkFjsGO(zvAhC94KnGZyU>rMD;%?ou`{ReVQ~=&cRHs*T^~^ z#~9*pH}xW=b(Ny4s_L~62fpj+rm>%xVijNha?{h_4os%ew9P-S!VvZ`DE=s1cEHGY zx0_->8rpuHlp_#xe3fU(ViF*-mF1q#&anCKm8}mpM^LU%R;n7}Tj9?iae`MA(D)R8q9i_{{7E1ShuEpvOaMUcVxEdZ_Bv()Ja z@=$ffmcZWTQ~lb}sLNlprMcSoUAr>wZl*5j_KHRkf>_KD>sOfkaHf@RKsso(SSlpU zOnn0_w9Swln{pnlry3^*5LYbKBUvxLs9vFpY*S7H^|`XeohuH17t#=5e_g)#q!?H* z`yp?-$n~Trb3xFp1}ao4Te6~tb*eo4nW+%rTlkUkTdL)S#mlH-Ef}d9Erj?0L}vP> z@M(L`J+~$!@1!u7X+hrcEf*gf3U#H%wc+4gTc7-6t%coY3I@=+cpKAD5NVx>{F7GZ zP&J8fg|?Ry+WvXrv>?m9oZ%1TbdlJLK~ZcqG6JZ`n1JWYkya?D;p!NW;G`r=a4oUv8#RiA2LC6fJm_(k4epwcpUNJ7N922gGsHsV+bRBo+21`g zfp?d}SDh1^Kq2a9?hq64NcSf+Ra`(XjP7kj1%5!|-nTBC*cZw~Yx(#&5BHqYvb{w@ zQ8tCQSX1O(Y@%3NgMS8m$74pUnB8Z|U5QZZEIeE^tKvhirvX^J|1O?@N}{b`7_^8p zDt1yUk))>pX(4@YA+olJ0JOIpTd${q^r4Fmy3}>e1nd|ut3f`KLIkG$5Has6--lgV zQ!~$r1#)L0qC|Z_v%CHBp?40~tsmCA)tshDBYKmzVNU>7&d_nAXi?~<_?LnvK}O>c1+z~1%s3LXr|RB9z%DP zO{UX_&Q$yUxJhS$A`hu(fjDB_>=lUCc^GWLnk>eIn9#i=+OrlI+Z|QWPcg;8{k&5? zYkBD%w3>Fqb$JBfAp^&0PBmpHfxr$PR#pz$K~V^PbzSzj@sv z`73gFq5oNQQq7*?8o&E^-wRb-YXGxt_1LyshYG93dVeCJkhq!?n^%CsKODAOjT_So zcsyZC#n0CtE=WN$=e&~ds`ZCUkv=!|V+*C%^IT42KWdoR@ zf!+^zZ~S+Hdxb&{M_scrUB)UeMKPl>)JID8YViO16IcKqgfNLkL%YlCODJy!=q1lpsSg-R>q_Mcw@Ct`iu^pI)`7C7j}GH3Z2 zUrqSK8c7x+7UsK7y>#AedQ`b|-4(+1WWTT+54RK-cUyR>p0cS7llHGhTcer5WD;b= zm%~~(VfgpgP4wuSnMjnu_%UIp^m`3$t8~eMIHaqthC$nsbH(*(xx(}1--T`_R*I1} z;Xc~L;3~^2C)TeyyS%BTF(}=E4-Z+vU!ETXfHW!F|1-{Fjl5`WY8F4iMEHaaB^bS0 zo>-h_*mDbiYMp0F@zJLs7+ho6Ef7s_XTyDT*^JMi#8}XZ@o5iXZ;K0_M@6$G+`OgQ zSMAt&mg4&8IfzYtvQk}=Nkn1RuP3@4p zu!%nB6F8BtF_AKxKE@^dS=hVi!>@M(LMx616Mh)SS2Af8q1kXr^xodTdyrf@Awy1G zV?m*I>Ft5PVkoQef7td(14)HjpEmNMdW^NXhQqf8TTq^2s!m1kY2%`fjo(v!CLo#+ zh7I@%qit}kcpZW9v|k(3nUpThPEONqzT1MXHCR&7x62x03X8!rzV8eDZSwp;9SIVT z2Rt=Px36_5dQTeBF}{|T?B&i&?qrf5hiQlAiq5V#{3kG2q*HwEZb$hd3hC~g`-Pt? z&DT=zY#e2hIm8Q0!r}J74Vn8mT8NmCU>%Z?p@m;0oZC{$c~LlOVZ65c_$-9_p-CK- zzX3z#g+a2l?0Q3+XbEBEae6&T#)~giHTbEqfnL%szT$dDAw>ZfHXryH$28N1>vKx3 zl1W#Ev0-$4A`j=Eo0dipWNt(Y&_BBmfskBw_zp^nQME+gBC z$5=CJ)B=VVYe;>~qPSmMlaHEW*LJ~&e-v#Rc$TU6s@6yj$fYA(M{n=RZi)4D(x$%x z^0cVWDMwmcnhX;r556r^^9qMI7%o;ba=f~$r85>zioh63Gg+4@@v1F+ZPfAKM8p~k zrFekPHxwCRx`K|rH`>Y9uo8)Gi2Xj^<40y9W$KRQMakb3Sc3TdLJALAk3c%{dh6In ziCZ^;TNm#=qn}GR-}`Nd#qS_uL-u--q!>|}fv4ArA)__|;k}*%hEIZA?9sKLsA)o~v{9QmEgh)AjJs%XFL{6T4Igh7zrDy&xKhaC zC=@GS+5OA@h{EX&MFYFS>%(5b^sMayCQ_B`BFa*_f|xHDeIZ;OvNswgUMkP z9RsBepht>9k-KtgY2QbTq2cjoyQFe_u}a0b={c{~{QPD9t;YsL<~HSoZ~^a`{A|it zJ1-z5c))(4GX#dfF_n1~I-@3Bt9!Dc{tdm7Ix?Sfp(c{6GdOto6(B-)jQ#LN3j@Wg z`Je{128EiQ>U-eHUBRxcJFrGS==NbFBg4(ztC%Uer3JnB;u22~pInPmyFeiLTINbv zJ?kUM|1XjwUqVw=jgz5_M_*JZm=Okkd8||>!}kXrH-AGh=I0boM`+{J`!;k|iWEV@9Sv4ODEz%eG<0Wpn zUjq!-OjDVr4oUATN4Cu{!ibKk6MPM4TJXe#9mhduZz!fOurl=qZuDr+e1aHnm*ooszYC3TPvV&ru@h!^e3-FQ7?I6j>iC^>1Je62 zKPi*iT@F=re_5*BAX>JJKBX)`h3~-5pY|$?q;@5ZwQ(fT5Xg`O;-scb93d@R4Y8AE zCBAbOU(1~6P=0F>v02mP;n-^+B`o6jKCIG^!P`s(Yafepv_8f9u$v0%A(cBew76}M zr`#mhk>p;k(phFXBW?>DE_D1HcU2hqwFqujq*Prrjb!V6JpnKQM{pS2eEr{j&&NqCoc6 zG1A`Ej!KetE6;tMA~HX;$N>D(^&q8~H;@^ih)g%5wz3gz`)5PeZP7&;E8a9++POyL z%_5?_&xnBF=2Ppdxez28G@gQp1WWHjwLX8Zw1lInH?*RCU70q^%a5%p+Rh6{WuD%iUvtcri z>DOOPG|#GhnFA7xid@vdF`(Pk2C%iL9Z%ioRd-c=Yn#B-CY@wL?-Y24b&`X&U4$kD z0?fOw09PT%ADhL;yjsoXXxDkNw)A97Z-9eakGH1KHNk|ga*0VN@oNnI@P9Ws;GYr} zQ8Cp#SD!8H!2~*nKzZ+mPH`cl$Lag>`MvJ@Gb#7DwU2-D4j_L2H`OPf zIE3&kOvAU;vtcPyg{0UaD{HHohNS4&KWY;f*Z+*tZZJ_ToefbYFMk(_?jtOIYvt=> z|E9Ss!@6<&;I$rmDRQ_e(-|0hf5`kg{ZZ`qV3!5;TR!`zD?#N&DbN=H;h+GD>|B#72n)FOX+o?>MVYXdN>eHg^Tfk z`mkmJs7XCOpjD^0ma&VQeswX{0Y;ca~LN zn)`_?K({KG7cR(66?5MaTMtRWT%cUMcr%{xsjYB6t$XJ~-?V#fJ8N53i>kZt%KrXe za`F$t^9%eLFdgy?j|ewcW3>h{6EhDE^(7SgA($DEOX0;Qm#!&W#?#|uEkwCn7Xd;) zvI^LryeS?< zN7`wCgXo;=KvUdSfaX`WQ-%Ggwj`sQHoOVuM7`R9*U_`674=QE=o&i)S!|05(xEiG zPCkB)3h_dJ26Wuz)m;OpYzo+DInM@iK;sqqliq$2H<53fL)+Vbs&g8^t z4-1^Ny98X$nl*0DE(vcuw;J-Jkc$iJK^%&kj*JstYu2RXu7AOt{K+xNLcx+TnjM2j?-gpWTxLFX2 z3f@OW3x6t~LJth7#rMYIw!WkU-HzKH`=uk}^A2+!DE_C~N8iKNryiD#3TnVpY&~gL zeMQpG&-A_zC$EN+sTg{PK4V85L#O{9-~tZ8G4zJSXo1)KjL$t-Y^Ib;TG97SX39qqUOm5e_n5(vtrnaFmtF$O|928Ff$FZiVB%NUy? zo-VlqTLX=GD#?Z8w_%}bx!F(ytzubOxU(r~y5a#h>Fo!#QXxi`_JQ5EYjtEhyw5@^ zY+}7Rpu=+j&s-jVIIFtBzHTp_J7j#>=r88zg=rDtg8&=+zU-4mF`;ldM*d2Sd+YmK zJ}O)zPn?i)7o~tN1xv?hwp6e3Rxl5a->Mxk&ZoY2)l5k0`IpsVz4w=Vp?-ev=zZB+ zXpFltfm*Iad&}XJ6W3cxtQ#!KdFLxqTW3HO_}(X9^&0*aGdam%L3Li9k(XP?n)bnm zUMEdU->qx3T{yA{tkD46;4#UHNuoP zcI8nt0-L2?uC+y&YJ%OXC*|M!ogSH&<#F zX;$Nlw+~r)kGd;H zzS$C>vHqmfCW>c}as| zn-(vvv-XeSZ|;abxYNzG%1Aooi>iCmMnbR#&}TE@1xCkpOfw&rN>q6LY!L;1$U_x> z$4(G{&paIq$fbQn>EmZ0r4MZt1n1!orUnoaE-`(kY-D%#*VruYQwRV3kuXi+YQV7n3&JSG zMH{@wC+@Qk#!@#6-*GLlawtHzCm8jrg>}DjSHAt#liI6J*WM{bZ{u3~v+9IAd_Fk& z1y>SL++I}iunj6e6VhfCQfccGa)b}3=dyF0XyMf2+f(HqhRUr41a9SHa~8aK9r z2-C3ebw;H{zC5^p@tL~C|2J=eN9hHTvOzzkOQ{B)9v|Hz>rQ%vE7q$)h%He+ob_8Q zlUu0W=-kT5p<2-Eyaw>eD|}v{mp9&WeAm*g!*raA?c*69My-)<#JF%-=;D_r=60r$ zn3>DCRHPM$GxcRlwOj|jj~9KA6mEkuIp_|!mc?p+TT4f+Rj7nZ{5d1*6QXdQBtvls z`Z<-I3Jp!UQ0w(ic_PvdLA*&dteCflFyV{r_xq3yXX%w=oS{sd3*Ur#2VPa;^Z41?tJy(Lj#DDs}hdSr-cTN<#DHN`uc^D=;DeXR` zmN{a}Gf3`7ete@{=!QF|{h~Gx)5R%P?tAviiSs9j=vlZ3{IRX1h(T_o;GGq*jw{Ma zBsd9kXHh29)iO&TYn$AhVd7#-&9bL6e4(rM*B0uu<8!rs0$W?mxGp=VSfb*JDLh_l=LB9RD&K$u)A)J0K6--MkvBe_gdo zr;%rpf4k;1CSqz64(yzlUDh3U&-GMLgC==UPPlV;;g0&&D43m83097InpqL!zDQk^#~q(* zNn}#LGKSWaR9dLCkP@Ddz$LZeT`~(@vwCY4Ud=xx_wrIWTfN7Oq@AXLIIgl_rEm(t z?t|Zwvf9|12QS6OKcR_J!8KoPK45XFXly4Oeo*@t>mVqMrk4YLRK|`d4wI)2v7&o1 zbu(Lc&u?Hr%fl+9g3QRqKx)V;VZe9oA#0apl_J&4o>?3Cy`wYpSwOvt%Ifc0Q5>`| z=bgjs*!z3g%gU+-^Q&`uslZj(GLX_USH?ASB~65GF0LY6v)k01{G(ZaUL^q-yXb>t zGbFw@-JwGhtye7ADqSBh=F7Nefl5-qXT}HJfXh>tgmLG`kKy(6o6YLqcLtsv2~fqz z{VhcPH8a6@28E?5>s$X_y&lZpA`u@JtXogL(iD>oPik^YR2>q)@Z#G~q(rY7>_k4S zksw=Xmm0FFDsAj8=puGeW#0-pm>`|*3j51x@=K$^&k2e!RK$~G;?w`}tBz{AA9Uav z>S+T!iYI-1blTRFIB5Bb*w796z2j6Ju3-)K{ae5J2QM7W90&H?{Idg~QGH8YDnc)6 zUYYJu)1^eHXiW}ViE${CD zSkxIN40@wo$w_0f-3>Hmdfmbn4mplw??QbjW`}!k`33I<>hFySPMMpGr`-k5yTxvq z-29%m&hwW198&%qEQ+8;C(R3u<;eO)-ZSFkePxGo>sNm3xAwom%KyQ?YOh={6_sNc zznB+l|4hKjP|cE5h9lnc>87pn{TC2hY;!^5Kl1|7nkZo z^E!G0t3)n)gGu6N`kU7tMdpcnn-4zHqT=d8mXkJJCU(7anEk@5i8FPa47O|8YNuBA zWchEX=Ft-H#YQna=-AUe{VVQ#X!%rejF%$l{PhN}C^*P&IN9W8s#f`rD~+kkobJ;q zOVid_3k0rnXuV!ik;#oHjhd-I04A+Eks^D%_Fb6HIuRhzIDx&6vLw!&696IUippU| zyiHpI&f;9Tk1;~=|6%GYgW8O?XmNLIaVxYyaW7ij-JRm@u0e_wFYXrH-L-gt;u74U z!Ck`R-nsMM`}O_Fe3Q)N?6db;Yp)fPT2^jFgki*Swa3kUYLEy)+iIB~m(xozDbQ#r zhs*J+`O2J3P$dKa3yROInO5eZ8#*Mn)YQ*29SRTn*h9W5P(wm19btWw00byHcvkcUqFH|QqX$oR1uTp15AzTGg|CT!_c6#K) z#?69QadWfpaU0@*pAHmv{j)|Dv2LJpHpCqV9oD5IDh7F^KMV7h`_rscFVi0&RM z!$NK_?Iv1rh~R1l-qqoJ}t|Lp-V2)f5w+>k2n&JST7H?3gvJVUn-!AjdW8vTHdPUyF+6d8bU@QCp@d2Hf z<_dhzhwn3a^hrWFwExsige7g==nEq}WucFx#9DITWoBist(842Zw)Xgj6FpP_ zdFIzY6ZD<8$8Eh~94yJ)g_*V2B}ilqZ6Ch$c<4d(-(@t|z$bW5AwYaba`HT@p*=>^Cp*sb#+_0v zHI!~upcq7jT+Makrn}c2O=bbf!#B#q_naz)-v6vq{8zEst%j7+M>|?tZ#Ye@D_nt~ z+kyC%Q6r-xIGn7fm$~-$xVTqeVjnE|-gY)~W2AY;-LTQPQ^uZ+9j$?_) z2tvJxoH8)iNmuR^6(yMbO=UA3<*6CZC&+etf$$G-HQh;Ja<5eDs+=QHt8?#?3uap; zA&unf7S+eDDu8BFv10i7pXs~y9;J8+Av#7n72z*g9r@H~E#^B<18Y>T+JipI{1>_hp+mc&5=y8}H3?--F z|7c%x`h1KdCl;YxiUZT3=G zC5Ekxa;QCC&p8_C)*3+z!h3%+|7 zQ58$A4rTi{kJYlZV7Bc}(s9&zK?bk<831C4r9PryJn~@f zRzFn29%+dqPhct< z9z62^rgih|@ut`haoYsz_9>dq^I!upA-g$Rc@Fw_9%6rd;`pYtqegaWnuFl`Cl#O1 zEcBNMM-BmhKL-AUNrpaLy-n*2ylv-B#mk3HpVsOGq@sF}=OK4VWyfq#LOWCoqz@yi zm9?rJ^J)g$$KDM?Vm;16aA(t69y%}npQximZNe+jhEAtVhjII_7^?MQFtXBIeS+;ssY*N2KFWsVCcWD*v zZ?5@mr=NLd2)oahARE)A37}_=`K&E_M4(Nx?K(N5=CwP}Sn1F;du7=UBxuX-pSwx=AHT5AilXY5d)z)Q(A4^V()si^Y zUULp^KQ~qF2g13ux~)vsJyu_E-Ed}*cJsJ!+}dfTbaUZj<9Ku?0}AyGhneNxcS>E{q@{B*MaQkihh?YpQpju!n9~9U=2e%I&)zD#aAgIWeFkT5B=#% z;;c6h>}`8wT7Z_M#VI5b(wEm zxmud$Y@8$Y1)~C4FuEIXrDE3$ctpUq*WBXC?aZ_a=~Q5Agdz%gh190^6aK;8s#wbU z#smDtjqC@^B)1kyYx<>VPPW#D9^Qd%n$;K;=ta~^@l{8+#>Ya>s&Y^feE9EU#!^a4 z=R{5;m4HSj1#s=ReeY;r76cJ9VU0BM@oHSaC5b1*4-^Q+cZMoUmV3hneeL<2xHL5} z3V{taaJ1-+k6BA|>CFW03B-d#FjrS-U4Ke*^!|D-&ZcVp>*h_BOV%FVa-siZ0eV&y zl$k|nZ_ZxqS)RFGeR}ISu&S7Ri#Q07J@qtvt7THg{OV{M7(jNl*zXR^%ZQ)MShOkC z>gjeoKymL1hLH-5ICQo+i5cDXFnsHUF@JWx!xoC1Mej?|#yYbr-0xAJ_QT3Rw#>g$ zTon!-w|V8REz{M1p$@XKP3f$p-!U{=ul`KX!4$2%5LMEWCG}uN9m(;W; z2Co5uh~!iJu~B6zz8-27?>d2AKnzD#M@Hv&13NnkNkY52+Gsd1$@lsAia5+C{#~`- z<4eUIq^_q7AVy}EYEyAFlUx6LS@mr3KI z*stc*l`qGcYA+f^o*S#GsxI(FF7f{pQM!Mf_a<1Xl#@yM3@>s4|8n32r5Aaf69Kim z9X^!4-Q->M+;_(Z-Je6r<3*qk%yuJ78ml9qDNrwM+hZf34;3qMKK(}x54X2@of~4j zfs^IjJ&n^XkOr~^8!BgBVk%6l$gIn|ZzKhy6O#TfOK;Z1{#`0VLs7nQV*A}m0nXH9 z0UF;HHUP%py3{Nwr)f(b5ogQ zblgfezB{TDg$*A<X$)$Lmt@YZC`g6VM||@RRQj3IJdQt{9MKevQWmb*iFFL4lWn^d&*sWvWy2?0 z7Mn0>4J`B{hCkT8F3n8qd*?I4xAC@f&Qfy;DYP;W2g~7Zc~i6(BR{=%2B(;fHg`uG zJf~%dT<_$KR}1xr?@yqxIlwz9CctxiVI@cS8K0Xd=vnj4nq;fhz`3k7%HZx!h9jkP zohY>#8U^hxILuktoTddXl?1j#r`i0Z!`?pFEYF==a&5)QzgJ}*aXbxxG*ZLO{o~2C zX;j{+8Nw{|aFO}tdFbNLdPEHFt;z_!zwDF6KJlqt5bmrHH*0-QGB*2HeBeOyVs$w( zT$uX?L&1sz<_?A(lSKG|b<+rod|$(*bxxLgwk<4&*_9`LcffM8sfeI*cabkwes@a< zcDO|(%T9Zs-3-39AR}3WZZ+#|?mu-RK(i1$nRLFv<#jT|^7WvyZvJ+~u+`QZP6++^ z0sp1GxxYU^sM3sbQyW~FbI*o+PkJ8hj-u$K|1AvYCC^BhX#q>Gx?GC%TE8Vo#K+Ji zi7LmL!SsC6_cc|Oz%N{^OA9Vpt?yLsAds9e0rcvYX*><=YiMIn?k##coZMr?#y3@N zLhJ~aqQj}IzO_LrcQQ)6v2&hRqs0kfl+t7%iAW9=^|obWDYNmAl+nc0lN#`ishg+i z5zY*v4@ku6z*O})BTze6{oNtZ`n<{igyxg{m!>Y zbfhVfH1b5!hH@N~F!d#&HAfDPp18~MQ-vZCNm#f-er>s58cE?x4g;C}=R%Wz(LXph zvdhtU)o19P`MK~Sf{Nf zJzA_~1gl)1ig&- zJRO%h=?e4!lgd~BRWHr^sgn(S>|5#ITxCKK%Yd5=wiyC2@XatKv|cGe+Pd!M`p9cC zdgsx+W-Nkvw)$Q0K=j<+{n&!XNr>B#60yXjb~amCA6fS z`e92L5EYMGqpNVv7JTC_j17XRTW!-f4*FgOBVhVdcFEa>Mwek zROTgp)VAbQtUDJgHCD;r*3aG#9QK@p9G&ahm&CP7Nb?HBAI_kirS)ct-JsBi(3@g_ zx9^hqVb&u^BLKENyqjEx$(phG3Bh%uQGff4PREzD%GiUgIZ_bssky^o?hTUYiMUxx zcH-qUXqpEQhc_0gJ|lvwRoLe5yT9`76KCe*Nm)DN26x}TMy}owZw*FfKszr3Y7vkf zTY6iyE2l>;y@O-)a@QB_^El@6INL;4h$*P-$XBemXj71#&xKicW<1GZiw*(jFjEz1 zP3T?Rp-y9n-cWf5KdhHmCuCvRH^H=#uyz5qGCvB{tiYJNe#BRQ^!rmA;KgS6vjd{n zwX@Q5Q$%Ixvy6}7)>>1ZaQvWwpM&ln%Az}z%%ggJy&7WnW#}Cehjx{5D~`!GIF|L_ z(4Zs9`@c_kXLxG_!$?O<2}^~NpnJ*c2?pl-k2Nn2@NaZ*OY%ZJ5h7=CZXf6fQ`fIJ zu;xhLZ-H)oHBOvN%pC>ApKFC*i!&l?6`j5H%2@w!MKWCZs`q692EUB_bYz54hb?|A z!6-+1Vz9H^=hQ?zK!YI#)NK$rYfF|%5c9^v^%Reft&5#lB+h7O4aE|hGSE6IAT-gz z63uU#mq#zbc~P6#b_R=YAl#p4APhvclsQS4q^sxgQ{OIUMRTyx+^&q58<9p$%W+m3 zS>tq|Qrn5HCRm@K4)rU%jI!_?pbe-{GmdG=xjM!3rK<+o#DBv4+n%-Ax|(T+-Lnh4*n$$wVg!yq4m!!XS}oEvL@O&--VOE2FnK!jZ9JQcf79QW4-x zwbc~qw*LcVblFRN;4hJByF8fqJ7Kxe%7+V5TyNc-K0SDta3h*64?W!LFTr@4KZZ#( zrtvOSJ2%u2-HvDYsq(zkV3P>zv{ekjY54}&%uzo6v?$h9G%nxpgL>}sXo&a?x_4lI z&r$_S;zNqQQfD$nHQ@bmBH7DC?Q<3X-Nuf0{~0d*8I%2-w?`-j>zt&*gjrIKNRQaX zjRwcq$I+T+UNThlx=nvFR0|XuqG&$&-WL{sXr|yyDI+|I@G!2~bZ#nN3hw}vJ=66V zGHlze3W~@=mpFsoOAx=y&JbBT+*elC>-Ejo^_QpGwB(CKy zBX8221)9yC9xf`KkfA~>;_M4w+Ooe`8{!)jsz;13{>1GmtY_y8 zFKJ%+o#L@jQjV*A>HNpTxK8|a5{$n$T5(B%&}B5Nsf9%L!J`YqQy;qaa5C{b8Tgf_ z#OZ@qt#kF_L2h7cp-&ciq%LzUOG8L?rMIFU_mHWt_NfzIo$_h@L40%3tE@r@)#10;mR)R@23*?! zGnKY#2ac5#hB}8LQ$pkm9v&&dv#|e_tEXtbUaqwVi_4F$vWD~10u0WCmc7T8vsRSw z6k&fodSBGGoM3bCRgA(x1}`C*qPJXdtRm?4f&JY%=}C3*l|r3uiQ((?%G9k#R!zAr zy~tQC!qp?`x=*Dp_uEJ$yutUj#FaA0Rf4cg=b^W6Mtw_!2+)czo>(^3U*XdP9%wCt z2mdN>qiLxN84U&`>#bp`vDiWn0`|#HSn+!UGT?5K?uu>!du6Xe}`6BAvRZ= zj#Y5Hp2Qf5&kdiad2J$Cu$i7E8i7z)K>(|bmO0y?W^MW1hEbJv*pwmPRm1M#AK738V5G2&uU4oaXg{EffgMu7UUO>4h`z#dnsfH39| zufdsM4oN0JS7L!V(BGUbF23d}nDY8rOZ=3h3Ay<~>F+GT=#5 zJ-j$BL^NYU6Y|Uh68J@{devD zkUl2Un;?S^{%>IO3vy_Gp3l+v__%iW18d-AOc%t#$#3v5UhoQ~_X54Q4+<4VM@RR+ zj4|Hpc|I#zgY;~-t=JFCvvv>BzJExwc5}%flSXtTe-Wn@!l7<)VWL8ZW%e(;2I~~_ zTV@B#meZ1=;MYpP0;V~kO=Ur1D!bIi&2!|*#pbpeMW}*So~A!{tG1o?&rX;!oI3La z&wL0coyq#Az`Ri4DUr1ma_c@9ceO0LnjoI@kYB2SgH^c}M`oUS+PX1|y$niPdI`BZMP^|B~br+E3>HIm6 z7LvS__;`m?^GOIW(W|g;Gj5)&M!3p*a5SY=+|u!tzbv!Gd~1yd7o%o%IaAIZGh&Dw z^gQUzccw5>5j*%ehw^H@bJyQuY7%Xsz8BX_c?#iLB5V~P7n>V&&q`t-uBC2G;c?B< zk#H0_ys?4=hRt{sv}0&{ZT(}A`04Yy<#5C0><{}8C?kTgUI{l*v-9JQ`fA0;AU}{e zo>XU31y;@5KfDE0rr*g;0h4kTgF>`#l5`}^WQ9GULMOL7(8FAr~!3S0nx zF8?A&Xt}thaP+BAOw(!1Z?yI?WiD!alHbQD)=WA+JO!A8KxEo zYl_BHX+8Bat+Dj6YZsu#TU2fAGVVg4H@3Sb4(w5h4AS?` zDmh1Qs93Vet4_(YVXN^g?pmw02g!}Pm9?@ilM0(x*6&SRL27R`TUv9jb^>7@fFm^4 z!=ieBWr(oM&-+sx64pn>OpC3}$vKBVS+pk>q?L%Tfv|Z_i^iq6b5K_8*41={1j0Q$ z76^y;vlh7BxZ4Tz($lw2`kQamX%VXA?Cn%H2Np>WAuxEfB}MVf$vj2O!e4xoGGzoY zZB_mgp#E=hAx-vqX8Th_%<)lY4MEFzRzG>;aBB5nrLoV#%ftRzF6+7O?hVQH2#j62 z(7s?~>%ujTh^Wj|}@U}fv9M3GKl<~(n%Wq$jB_$ATeC(-AdPE%%) zsXl2VcZfV?uVQf<&PIM-N(SsPi4z^b@oKN4(p08Aq@>byCmWhq(n1=s1>l=v#LAzzLd?lrgHDeG>TWbw(w zz^6BRi2CVT@35!EPX4qm`dMG`_Ii59ZHw_N$u#VXM9)2oJ6j9yDaM->#Wd_qT7o$&OvU_gMB_`edlR@&C$AmI_ab!xg~z=hF-FHU||No-YKHm(V=?M}^0maP({ zw4+IYQ*&wCq)x4^JkT7(Ys0r{`KJE-bu%4jF$?X)HXvKnnqJ{;5NoBLDE6M>7Dgsh zOhyogU=m(?EJSWNTY@mzCSgkviK|E|!Ps^Z))M@;$ARu_mnW=UKbUVcL)u5=Z|V~; z%IUM7u-_lDq2ZkDwj$s?kcE6Khqq}V9Om8Gse1)wM(MCeC0X52b!O@`4rbL<_Nt~8 zCzH7%&8YCjm`9fKbV3jvhu3K!7iNxc^v~xL+XL7#Jq|C1g-s{U#OYZAIn~$Ubuk0N z;_n1yvzN^-XdDp^H47#d*_sKX{Pj2=NmJZ^N*u-^rBpahnyb^wi9~2}w=RKTXQ^Oo zfOC)D5tdZ+1WaZOMgYO2*f)A>MeLhW%RgR#{Cc+YA(-49&7J%NrfzNC3K6DPm!>LrcO7pGSG zVgJ!^Sc*gRlP}!uJWx;wx}zrX)vJ1bmWgOPr=eT9h?F3GJe|$S$hD*LHDDUF$95B} zo0s*MTpV0y`FiZbIRseO9J;$y4P(S;GM?U++jYyVE$3B4w8NR5JOJ$j02f7(em}4E z&Nbp=R*BT9mrT8dWRe-09iSPV;lBEve2E#>&-R;EAx;@EE&NEx>EBwj0ZLaw*#y^`aYeF|=mm3&2hNjNF+S zf2cZWE)@wt_+%vEnCv-$)Lxb5a(%+m6QOo&Wpx=K0&nK2@AS^Rxky^7pY{MD3L^9# z+_$HwFFdBfGgs_e{Jh<{QFvE*r}ZtYzT^=e-3VGtm$*-YKU#8kTE`^G+|RagW+_Z* z$@*4%zO=QbO&@u+w6-I5wb3&Er>4S#d4cb&M@k5mDMhfp56*y_xGD(z7YK)erF6R&}VpVxY$fOGnA>qJ^AO;^q~##?ubLx;RV<=lcAk zptVY2@4X!AT~iXOV3x)XFWwNBFFV~QSfaH$9LaKc2X4H{E+#<lGdU{D?nFe9#~dB{3^BM| z!{9I?Lin1tTQaqp>Oyw_UDtSV+n7sz7EtuDPur}c$bfm zjY3NkR*(^qh!sd7Q&nO?h zHAz$wO-%}%3cOnfFbhIqttFd0;g0QdCL{m2ge-~I=W8Fr)e{m}?mxBuN)dl<@_ipX zOL&PhjoO?6fxSU?6VDAz9UV`EnuTj?Yr&leI);Y(3);r7@f23kbG6UrIQGHvEMH;f z@fteT`l(gsrxnS+4QQrXPB{SAw<_^3oEwGqVqd!gd*Z4XYj#yU7z)lS`Tjk|Ad z_|(sDFN387+8Sn8o2norJLAh}09hgP6jf@I${~j}g#$BJeEpJ)0arBvt3n5!-V95D zN4SOoojF&c@g_7KxJNb;-c_QF>VUE0#1AhoGZbJ0biy)0UBTp}xSvL#hWc9&| z)P$;e9-6fUcrTjBWn&f?7$Jk*OHG@ZZ7VMX_tduZ@7r#fKZHd~pI+G=Mud^YA4$p_ zcP%f0KQ=^zOA-Ny2CqJv*RNRQ5v|lonPl1}EOr~%OHcor4m{MK`*~m#Y`GVFS!t+z zf+wdLu$r`;HEUs)>!DTDZtJVfz{7uAX9PShJ1&&MBa_nq5bpEztn+SNj0cep@T+&> z&XoCf9NGRa((@s4qPzC3c2`(fQMEnXubD3frUe!6!cz5Za|l$=n;;M2gTrw{NUEl7 z{nUA*b$g8qSBgQDJF*bz06OOg?Ckj^+J~H|-_Omw+tp&x=y_JSc-t1JZA)IWW4p+W zkP6wZM-nNq$nHaYzLkE`bx_8JbtUaPyzd6%UYyF96h}e3(3dNR=BC_M54gd`6|V*( z3(YO@mT1Ek4kL6ge}xy^kea`(Rt|H6r;pMGFUeqIN%?}wY&V0M{GOlg;UDb!#79p< zGkU!M5ax(qtT6F*IS|4lI{&CQ8;K~pTIHChcMEWSD8d6fWbmHm;HhPruip^kMKPG% z=Gl18-)Q!m;)PE5fogf}epj&Qa`KzT(`etVtbwGT!u#I_S0hjK4j&Y`{~erX8#S3W zy)y${v-N2E$)tUrX+8^i*RYuSivNdD)6di@Oy}&W)1Fie5O1Y6VU$0hvci&4bV!Ko z9dFMF5{1b^`ka~7#v78>s4e4MtV?HGQE4`iNc0t0n67^|2&EwCsK_j@o!nROE`1`y zoWP79s8QY8b^Jccp{WW?K+7(|!#`l%bUBQpu#wjy=t^6B{LE zhaILA`ab(?RY$`$0ST)RbaX?H!}y4tGvXOnyMKORB`gN@n=w&?=V-=4I=__BFqP`v zoI4E$e)n(_dmmy3;ppj>-VPn~CK%*{t|?%D5iNg4pUqQ;+C8*f*$q7+6p&Q z2BzRuj4C!$} zJB#lQ7V&<$Xtgkj8`z ze;AQD%i{Vns2)n{q%QTA(SyRX# zxfsX)d`BzQw0!e?6R)=7zx;;r8MOtA-}MD zdbysSv*&4lgFbIIecSwdj8Y@R)m#L~MY{3~3=NIuQ^(9~Z)4y9#s84dBEZGYRTuG! zPXF%ZLY1<0vWO^A|M1>M2~kyIHRfUG>w<@y?S zRnx*NegtrsTA%mr`YApfm1=XbzIB8dMvyJp_hTqvCi4gH_m|>aiI)tc1=nh*6udpR zEt^~6yEJuQ>~oXD^J*?Rv)Q{NNgu=*(-O%biq!eq`+_$J{z2fWmqEUAwVs&cT*1Ts z#5}a4{lKAa-lV-cy}(jB#t8+CdW`d5ZPC<@A2l5uj67M@3dB`jB#7w4gh)J?M$2V0 z^$<7Zn4gR#vvB4Y`{XZvX{xzzEC)d_00+{x3jCK;J_$#7x*g6dX73wM_?S|c<{dhr zI}*4qq_(%Ih~{kcW>+-?>z2f|W=I}n8+X3C+Ac~0$ot?$_#gyw!-b83e?7y1`ym~f z(Fs8n`UQVNeKnf5MWO4fwd`wL^bkSRDZ&&eREtWb$V{jR&mR zt$Hy-cHQ)*4_zAHT6c|%@f>>l`_bD*3g$*3-7zB+T-Hw%Io{e8p*1)da!?`i)|hV; z3{aBh3JA&GY^e}rY2@N@PFkZI>8H9N%Cg6+Zq02TU{`2w;Z&hom`55T+Q}wQvkh*^ zfO68=ED;lY+i#eHl>%&KUMFTc8@$QO!zd$AozIwf4}<=SxJM^bd}oQ{VepHs;>JQx zGZk&M@R2S@18#R#;wnSS?Uv34=MPwp-ga1us+hrDtpZg3Km)>KKcwh~=6ft$?zQM83A=IaM9}RIvt<+f}Rv$>XUn!nC%~evJ zrM`3bdt2(e9eV+z>9I!gMv#ZvszFQ`MZ<4C7O+)bdC2vb8Nd1h#&wN+!_fAako5OO zv%h@voyM$$K@CJOl^Nb|9|;uT7nsBWWu5#5a8JbBL#Q6pY;?a^)D1~wjTr=o;B-@d z98koy+*B9-Zs#j6t5HDt4twT^b;_*TuLY+)SWi@tqqd$N`5q5i)i$6O>U{9=a`u*g z=2sDT#7e7OAkvctqT2Y($ATaxWkN=dx8!v~^8G{5-w&BB2~!xwQtvhVvh_(+U06Bf ziyRYqn$7kufr?(z0Pn?&K z7yaOF%M(}&fBjOL>l=+7^f2hZgP->wHXgym%PVd3A$D`i=?&5wu+yQ@$6KrVF-SxuKseeQ=plgrm6$*XkWKKx= z`KZqoUbs?1hw_h@mMIGkyLWA5bJEFGMbhdX9$w8dLg(JXW<+-j=wV*c9yVe4&&Tw_ zDY(j$=wd-#&F-G3#+u7{b%rt-pRNs`RejL&;-V21?qsqHJl};BqfXX?SRFrRCI?Q` z509uI-&SR}zqPJ|aMX}Br;OvBwQO~z+Fi8Hv?w+k$&Ws?G#RO5Wj8qX_b=cxK!=9xG z)xNpb1Sf1)Kzm~hP7Ym;Y%f>`w+)Ra1b?DmLOi=`4zmYoXF|n4`~3#`PBo&;_`#^s zSo(s^P|{DS*+3dqND-J1ARKGUncKESyAbfV87P~K6`Fzi(6HQ;pX%uo@vEQVL`U#5 zMgUg(YgUpQaZp!A<{X7QF*5Z!FKm!dsPT9SS>?IHHHWpY)N@G>vZbx2dM!Ola98w4 zitM>wW!mel3W|FJhsmiEA1jwM%oa-S@1hkYLRcgvWFy;_z{6~@;hXzlu80x+1f>!~ z>)sc6i4r@gk@C*>GW!=++L?f|SI7NKfiN;JNoO+T1?-c<0C3KC_3Md?$a|Oq^eozA z8e2F%(2*956^&>7$jA@E1a`odV#eVQP?M!BH| zScJMp1?Nh#@8&+EL4Xv?s0jI%s2DNuf8Gh2;Ay!&E7uOD3&z@fcKpT{wUjJb92rua zKcyMOyo8ZlaMbi?mGx=SVy@awX%m>?fn`a!w<*zIbVy4c5~>0ylOz;sVr2MZ6_Dtv z|AZ~B5y?=T!sD>UMn0qMaP?u4hpTDVqLr|Kh zB_T>4y_ijhz9zb=sS+l-*TX)Sh@NoZC5wJ3te}E-QJaTDfJH1MPzwFRO}i80mNdN% zpPq?_Lsy9ei@&dlg9vOlVZ*TtaDYnQOTrSTa_rdAdb=mioZ@CG`sn-Uqi!=^HrIdA z&5HW+sc5QSmO(#32I^8v#WjSGCy3YZF0z!9Dc;=qDz{bpmAZ;oHkI@pET%JMrX@Qc zwElAa7v`}p8#yf+SBz-=+!{BkQ(e{YFr`lxer$a!p;6+cf`_!wq(*MX`5@2?#Egg& z*CIni(ohcr=Y#KI$i4uIkiyyQjKSQI(5mkTTPQHW<{XUE(9|$!Fq2uKX<|Yv8~Bty z!#&r=Ns=2#h^Yg-1j1E1P62Bf16eSNPW8WUmjWS6Fc08EVdOriw>ziCo}Q_vr*F!_ zkDru6yD8d6+aH21KRDTt_5jsHHv&PxnNP4Del=vemV+gj zF>Q>FAqLkmC^HDKe6Yy+mK%Xu6KpbVg@+E?!J{Em8486FqU@oz*fbX>${CxzhpZhy zD*N5&ZlVS_;i$n$mufJPdbB;k&V0bDwS(R?&$CDiX0aoQQ* z6f)Pe_h@jj+xp(6P!FEJPIXx*W%vbp+4Qf^{p%_mKKh%YVqt$SvXGyK1&;^!wmyaZ z4};jeXYH=22XaJV%3?W|po1W0G)V$)1zXi^CCJZNr1@Z&N-{F!7BJTGPp|RRv7HAC z35=;W&E*t2&g13RMzX>~ZP^yT@IN>@OD#ljhbK|qF+@7mY1gqHq+?1BtH}vQST$MZ z78)UlY{|Q%a`nlR-bw+~YVKVLS6c|{P3*4S-hXyhv8WrTGR4-mVX-yL6Ln+)G741( z)$YV!VFZCiY6DC>WN}gKo`VDSQhzXx2vrYCyaf`qgWjp?m`bdESPs6M#)dvqNU8JE z!L4-Eetk|ayGrT;JXmPJ1&rDGs1Lg7GzzT9tKUs9__iN*Chr|k%zFshZ&no~c zuz{x#o1k;*cxpd{HKS8qL6rrwr+X3PKrhCMZH=|-&Peo7T)e$wL@;77tc4#}a3>#| z_%FMM%7pS_>E_)fm+-6W2WZRfF%sTo5ArXmv#bRSvwyh4V)>2bI;^n0;l}Fv56f1g zyQejB9`XtLy8oHfI@FB}vF3s-qu)=tJURlGR=AD2X=VlNZn27_5&o=(_i8c0+wb-# z{a=OS1V_XO2f-|^OvpZjYEmNjb?yB44_fdZ?5vs#rE5Fh}*@v7EO>da{(mkZc^d#@FZ+udlfG zu1Q~K1XihDhc%OEW)sb?oE<*MC2pL^?Ono*YvxseYyT#l)~VzRqge zOVwUV>#@oj<#!S&_FBE+h)BP+b)uE#f# z?neY3MLhH&3-_6GY)5_0-MSBYyXOyhx&gR}yli7%7l}L-y)4JSehlpo9-;92wfUH{ zxeaj&daiaDT2k{RY}axVYUtAJ?h8WUXW3RhFpNSVy>F@bB8zh9er z3lGZ;)8qh@$_SQC2UNgmldZCQ@O4DOPZ7Y%+@6}FBKrduzxMolw;<0Pq&V{NW?Nn=BNnJyEsp zj9`C1?1(s^;QD_4$&CL%VSpL#CgzPJEfbx-rXHh9UIsZN%`H;!&|*t|G`*Kl_dBt< z{Z5Zrb+;Kp604n`;iyI66(SviY(D^2%Owv%V~ zZ!eiWR8Rauq!4v9L`r3)sdEqW`z)KNU%Q^F_%;4L{-cnDo9;yP`Wd4~8KnlNIgtIf zCSYkKC7Jf6zCGexndBySOZ3*l+{raKzJ1?@abD8l)UPREnkvB`8?Xv&0^Od^=}lR@ z;P%u6+!h`<>|PWu_HXTpo;u4;KeK@82IK8=Jp(E8((X`rLvxe8Vd|O5xr-*UbL=a4}Yl%f3?%PP(MMv;ecknEoRP^jH8dbq>GoA-FCCpS{XgM z7XFyPcZfT!ct&x3=$m$=j)dwGH%(YrdK#SS96@vl-^Ag`bXhPLmi&S0D(w%(Y$RBB zTmTRqli#y50Y*HQ>HxeOoex}gR}V17`oTyU$|8j+hPX5QyDllpw>AweEL(Hvl=Fxl zE|?Txi-YR(M^LZ*@oo}N+dUOe#ny2ncZ9zy)DQ`Ii{}c$kK=g@8_GdvE>J2PwU!Z zEPIt;QwH2 zcHaSHhQKVnlZ}p{YH&u?<{V1WYZQCO2N+TnEDi|7rR8mf2{QkfZ{hX(U8xlI^w?5P z$P+j0OM$IauReuqwKX+Y|IuAz2ONn99k}EuMPLVBg!*5EQoh(~o}bBcf|Uy&QJU>0 zX?~M(adNNYXg2|BdDLEfd7JgIdBb`0VvwYm1Z9$|{b``X4xRrj_3WKqh~cKbHT#3& z&d?k^9oaznsv(tzn5oS;TjqEl)m@DG6&%ehw*XJ@fxy#CW=bH1GmDmCfa1-4;I$p(x z`7Y51zCn6h?TOx+>*a=MCC@UVTFe?h%czpQjkje*K;)3xgWK!gM`Miq`Ufh|J0uBrZ-1a5mr%GR)g=`s-CS?7OU^g=Dab3qaClCB)~84ub_|DZPZYR4E1|Wk1c3FlMK=+ zl@%sDP{qC8V*A3%(ni}3PJ9ruF60?jiL{sb z?_KHLBO^`FG-sG@PQ&hFVqBqv_!cndZ0JKoiJKSnK&Db zY~Qwkcu&>!Q}ezvJ{~Mt5ga1RVS{DJa=LXqPvnnZYfc4NWgkQd<{G16(lw)A8(F9~ z^o*|fW5;F@)U{eRPn?U|3hSi04b^>fUnCXW@In9(du;QXvk+47FK%G*%y6Pb`;GKW z12vbje0;_Jr()fDqnHXbuE>1ly6|jP?11I1>`oK6-{f3Rdvd(yhlXk=pX}Ort4P*K zE`m63ZfST=&*r?btM^wqgW%Y*6EpfeWFlCV^Qf6CQdmakJ8HK7O@REMQ%9_h0MyCQ zspG$91Gshdy$l4nP2$Gq-)6TG2286)ywlR%XInIq7ipByuc>7;b3m^~#t@vxj&f7& z!wt`t%a)twQ@}u8P`4Jj^yQDZJ2q3pU|EXG%j0H?jmr)nDUb>N!pXnS{K8L6MfzL+ zJ4|l14k%#oFQ7{#a$8Wp6Xyfcj)MZ#-r$7nr^ci>{qo0WdyE29PqSFoYm05C@ibTM z24B7HHzc^I&ujB>5M*W&p;!Ny=A0P^tUXiV^^fNjJO%ED13Jt-mSwe$hPoIj;2C^F z^jhfGpX1h6Qawd^DZBCGpVSwBYaoAmJEDj`v#cZE$f`0&cYb~ySI0NPq#ZIc%*MNx zptr`9s3FtB6F%*pBF0Tf*1<^dSGJN9iIlSRZ4WCa`7f2UHt{mi#$m#r@#mxesDLBz zF`+H(^+Q#OA}VOr2|%X&qC@NJ{mV)BA*ee3kYC9Zi|QADxi`>NE*nnhnbf5a?b#hC`C&{{s{=JJ9-oUBNyjl(fwIeY2Uaq8_Y`1m zNv;wfcIFVpRD7**^;gs3ffU8EWwFI$3S^z6yQv&j)b7;Yc{lZ#7M%hrj;sUI(rQlC zetm3mc%$8$DC{t`u~)p}{|vK>X{WW0p!u1QhhZvFdHx}CppSs_m0Q0|x`Qw#CA0CK z+kEg@+(Om>)pE9L>AafwcIyW&--IB^5g|Z>f#zxyfJr@qLgTA0Tug#0TT~$mzzep!@Dqo6h3o?~_`~$fn92G4s0K>uFIM*su8{pK9uJDCaAoHd+^hDev+98;r!Kf~E$Fb_eMy39>t9v~G$0?8gf_aIvjg5K z)>(03KO16j$sY;-lMq{eP!q2pJ2C2 zhiHVETGGny+xM-L+TIE0*7Vf0xK5c`v2<$qH9yHy%`RrlSF*LV0H?nTdV%(!#&t>X z|J`gin~o^6LSK;xv)Zj;VvGi*r@T?7)&!`N+B!OCu+RXo>n4YlR&f+|4ZzJVR0JM~ z?2-Nx^U4duZ(j%n+~Tb$xG5(1H~aEAkEHpvo=x{AidMg^ z?Y;&4>#9=oB1UFbSl=8n%jd9F^|v^hJkEr})ds_c!zAa3`WHz{k6 z2B3U%sHs}bNIv35V&8$;)vci>v!Z5wmJBx@jVh=xb&Ll` z=)3-J-TPPP?ei!S@x4Eq2^^jXPuZRWa61%@hG;h#24$06*|42`T9>Li+5XQ!G5fN? z#Cn?LL`nsXVR|rV5v0B=3;5a=sp* zR%PGAuYu47W3;}fS+gs+piP8S2z3{;1LsGYtEgrHUBI0*#ut80YXj|)U{ruR#mQ?9hZ~2?Tr!W&~ub6rFGWeM5YVMmb2kRxe>Cg6KuOGU+>l`^S!>IT4 zJ%WTqWlmpc0JS>$#Ui6M7RxzEQ^K6FLi%GOb;Z?t%Z~Csc5+^ufNh5~j}8X!PgU8E z9f|T$L&U?FXzKdTmsC)5IfCa8Sflf5u@!eNV6g+`=aDZOqJ}(QqQ81{upkzRVq5~X zcxZrimyk$C5)!_)2>lUOgAC*$CuEsM*4-2V{r1{xj=>RUBR6z(eekszPr*A{%>k&p zg98h00PGf~v7fnZ@JdzL$zpfM$Gn9YfW4XnF{U(xGsubmj`QUdc_>^fsrHBr$S`9_-~CXyFZ z7y1Yr=-_`gfG6f3ANl7F?Y7qVxlGru`HQl^E}dspmN%WavFv8Qt=I>N4HGNqXJ^a}%(!j8_!_D0*{is+P)NYu3=((-U_1`MI1TO%_S9zb z9E$hc%%J{|YTK_{)YEK;fg7rftDP&mrN`xi28<7BJkjJCG|eX-M(w9-b-4))r5;=r z25r^p={jn9M*I9+6v`}GunCV`A~&(5Y(x!B+#7X*?zc(bbT};zQ^35vYw+9o`j0>l z?a@czC5v6!r^v8AB26*r)-|T6zM+ISn;y`c8^Qnbyyi(%A~KCjyKBAAYXPV22OAzx z_!~1O>@KGLpfKq0v*>>ryeBxxVEezfq$9+uP>l(D-u>(o;#`~sL1c4Pu;R1f!hXuZ9)wkk_>P+ zPvM1-4O-Buk(<*ta`NID*atP|9SaYL9|A`Tn?K_Q%tNkj-=3oR75hj+%rnP@jt)r6 z8?Wsb{|k0~%b8AA(N?UK)(hid)5^zZ(S7HoJ)FbFwZ&aogY1%mrIerU#QQfzVY2f2 zl`a0Ct6sd9rhZsSmHXhQhC;fLH>qtrbFdnjaP9NM&HXz5MmqI4%B46;z6;vic)aBTxc9hiKzgy8r~hd(jeI{ z$4bQEk0RD3()aBg(}S{^xvJg*MZl{1n>Qv%to&1XkH`e3H!ZW;1jxEhux<|L?KJb@J42wMe?uw z_^q+Pw?9SrX6#>tL1t;@WQQyLBnbqD_JAiQkRKLL9z4Q;ZZeAbkA~_g=i{sa#@6vK zo>I)Nuk}eTf1ryGFvt5w$MvM6X#zQv_T>7eddbs;p5@_?!Q9maspg7@<7!+(cH3y` zRQ(_KzxZ3xN^V*c({ipT>2TWkhyJ2K%)>!b3adh>n-5gYit934XALbZJ59U`yFutu ze-Xp5v^R3~P{rM&24I{3ncL=5#nkU6iycKsFT5T_`i&Tsj88o!SPk5L3^PfH13W=Xh1w|CEmLU%8iuZz`@nH zB3ql_6LxA%sEg$pwBrZ@veUr#kB|d=|9eBzbBH2iGQ3MZ+-wR};PDO=s($iW{p3zD zR%Pa9xjr*HU#+%%M>5zFIWd~F$CqCt`^d`>GZ^A59c9{ zDQ}&H5x)%Ecr|ptHKK0uC=MmL#RyV3X{x>sBfBtsfSF9&pN||y#+qK)$wfbOwjIMS zZyY8_8^+Eyag+jk!hNR<$)ml&a=891ynac}ACjHhmjsG%27xYv`GVw(} z?r`>heS4{N(E=2(bC+7puY3DF1Ai6g=#`%-Gn!2l`5P)ygQLf_qN!dh!o{%KQw=A} zU_t)g=j8H?6e>p|zfbR3!e=xv>eP1@)qp!~j27hDW>6N96{di-AAQPn_26oY)igmh zRU_ALCJ0TQ%7;R6k0=WjC3hMHdQn4qlk=u=cdpc#ya(^`b87O4s5gsUo9MKB!YYn6 zi2>E6qExPgq`89yHS9lNB`I{=8|f1h>SKPr9`fEK${QWX?9N(ygC}_aX&Y&{YgFyP z!nk&MLDgT z-w%{m5a%xUy7-s@fXIy6$;M^>4ug}2TQZ56PbozxNS8OWt=xtn85`e|32GEZGb2_h zJjknSgXD}t;|q>?bmiZ&?a_ce`fVdj8(1-O@bspm-e4PCd-%XSp~!(mG2;$Bik@NF z@XEZ-Qr8eH08c0S;R67d@PvD1vKL|&ie(tL(Z|F>ZPrcZd9OOtQLxytN`?d0{Ckgl z+ADDE$zay+H1qk(W(=ffdU$rrta}7cC8$C+hud_+^?U+m3XPSF&&Zyv-@k+6_|9p zOfi99tDxjZq_U6z^451DC#|9EOO2LjTL)n;2lxNu!?G#-f8!c3qVK@Nb-$8d?~*UC z<}^1uz64WO+Kh78Mk&fm;s(=%OYz}S(C_v6ZH2N;zs<@C2tV3A&0jhnDXx*@6MtcA zQ2D$2@>Y|sb_N+@MVn-{g9HHE6zV?|s>guKSe10=6v{#FL zfbIJPGl5gJkI8hmf;)PjTwjSKJQqTq}dlc4c~Ip|mRT z2R!PibNfu_T=#~KhN=8F&)`v*PDUmcQftAA4pD6;3lHxqddAaf|C#lTy?^+A^8)gpTb)ctBmh_5-kTbC3$WrV48^^bOxvo)NmdJ zO%n>WzLN}44|XCY_ySO+oWP-o1CBjiv#vAXd?PZCP5nqn?!Mpr>Jd3?Y0Og36jcv5 za}p%+%dfNxFa-D$)GGN{%UxHPSHIm>OP*0i$GfVwfU>x0V%&a4cZC`1?lc@p6t;8E zyyPJDRI;CcwBWvV&qWS*)s6nbp&dI_(#9FP8_Md2-YhB0&Xj+QIUnq!L`BM2)fu%r z%ViCg_pwfH6Jeq?Al{7^WYAvSn4=fj_*Set0HDC&X+$^WgNxa_YRPR`L{&uEi*8el z9`hQw?CLe{icitQ));j;1MWaJDhKaFU%Kfy`4Z;b4bEKA8$QJSu~gD4Lv$FAS`|L~ zM-#SmeaY`6j8#E{>t^HTZok|(J-ojo>dPA$hp%9xuF>SPkNXhWJFPi!QW9z>ez9P? z6vUdDg~V4TDO(WeUh)|r`mpZy9~&i%_~6`hlc>o z9f4izH%>)44-IiZ5^ zx$j4c?XZly3rFY+7QEx@UR6N1aM~Grpj&i(pb&gbK#a@_+#nG9`cLb`#&u)Jx)Jn% zX;wqwS?!AyW-R1W$0}2EZCrZ5;UvN#_BJjf3=hDIqa_5MW)^1TUuXck$JcofiBCP; z+1W;;0|<0&ITHmonFgz1o>ci^_f$M7E?V%@7%IDK;lXHEd(vn%MQ#;n5mHnG8vh{b zCTsSoxjN(=p8W0({0g4<%jODp`d7~^A%v}x*8yLGn%KqO<#yk$TrNE0jY)zf3`4viwovjFAf~Syal~6w}+twjc9uAw>#SS<+>Q zfOVJ6>V&&S{_nR6Fe6?2B>2x7FH-U7zA=0=;*aF#Sm$IeqU^?0Y z!FjZ76zYEK*_+W~AGPm8%5&QTOt}2r+u3G{K(yUk?P|QVtFT(g-bNYGy6c8GwNt#5 zUV6aqekt*>cy6m!TK181AfpLYN0n+hcXi%EotNXlT*{tg%2j#YLZ*2CLsH)d8X4Of z+VBkI4f6nQwzbxu5BXcgPK%+E^?yPscto3S1XC4Pq#kdm2d%`GYcxLvIRzCe zwWzoHn@)4D1hCb67mJMHmjO=Y?LF3=DIj-GNhm|vU=Z(h0d;GBT*PH1H2zzedbnv? z{EVSg79HDY4sfO^6Qjw6>7z!MC8oy&`?W5c6QpB$B!DqUcc?~`cd$|}lQwIxjwr6V zur_{%6dM+W&+uMQZl!IWc&2UMiYB;5rg%a4S2^RA=tqimcXV{K33M3g_k5*-vfN-6 z>5a51lCkfCM<0^#7n8I?w%HbUdwS z$5Lm=PQM+`Wl+iv`xC^RY2CIPw@S z#%k!9JI7mt{EQrw`0p7BXuHA1w!psmPxz8;iSJ(26f4>|+YX}IsvK-fiK%O*7vGK> zC8{Fk8q?(;E6sfW4qThjKzBA54#bWvWsJUm%dMfRq*8Peov!|Els@Oi@dHUKQ9wf| zO4&Ol`;5Dv1y1KJp$bN0wzTxRes9*(xmlkd;=K}cDI?bk;e-Y2hlEN=IRmZR9rwYO z+`78o3h2mub8shCw&NwX-)B3I@6qg{eis>C$hTAhvOM!8%4^}J%dkEQ$19if{e;ii;m0p_;R;K=$e0Dubzq19upSMc=x zw3JOaySsXOXY?9yKeu;GjnFL48R7lb_@vLEycDfp4BWZ>lM`@y<5}gpFSMZ7ior=x z>tvTrF~=y{i9RTBi;{7(tqk3)WTlHi2MX|A^xRBSCPl)>FiFX#~VpZ`()OJ!vL*0k7X zJG(!17Ef<_@8mabT3WleFBNG5qAc&CEv>@BilU=YdhUj}yf#B_f5Uv?DwvDlZbg>G z4jdnKU%Pa6A|Rer_opu;+93A+0R`EM94ZzGte6N?i-VSGI7n2+PNs%rUZMj{mT399 zn!Jhj7F{ckk<2&(Zv>)dLQ$8!-T+#9+o~i_Vjr%F9`4&sLKE6@o+-{vzmbf9pY+X) z@5lhGs^a#lYv-l=HaoA0@$7G0zaA%FVBnU)yOmq_Fb$<|uFp#LyD`N=RYX7iL8f|*NcSc`Tu&cP?=vO5 z3)2S(z-q;6{z#Vj7&T`6tR8^(6AOzNJFlS!BpQ!A_Z9AM(fouYpm{8v_zWbYU3Ap% zO7RZRzw(WmiP!8}gH7aU|F?lrWN`*oRju{nR(apfeEJ%}AMQ+#^FYX<_1-oP zfkj}Y@+-ibe^rQ1%7t`DEL11Xa#rIw-1&WWQUtHIQTCWWE8C1V>-p$7A4!R;L=>G5 z=i5P*V^aLylsTF7I2-{RA%BM+NlJ|O&pFnX-3xJ3@$!`( z9*ua3Lg?0;Pm0Sn8+nWAU+B1wse7ToKAu4tz_>_@gD51~ilA^z6TWT+yxaeJylRxB ziA0~=b0-aShYMsNa!*qPoA>O936CO)zA_>SdUlNEaoO|9>@in}zr5!91NjJ~gj1H_ zYgIH{!e>f!lsDqo8jflc$&gZGUy*J_e#hvJ{Fa1%U+&V}$tE9Fo3WK@D@M=SqT+I_ z0Ykj-532QddaI5#y3hLZ;zW|I&303RD_^;3q|3H#Qcz>aiBOvO%0U77(_s|hGfMNW zUuwJR4zDr2aE6VU`rG~~IXFp(X32gaxvnXQF}!nf}tBL_K1V@I?}z8oq2^>`(8KhjpTA zU>$QJU?WF%k~b}U7B4nNL;S%!#^aH{2oIJz{v*fovSV9KT6FF8wdn6}x1TSU>N_HU zHY^m{k>lo#fW7KBlNjpGZ~-NJa;dJTr1f8oK~oMdq}a!}+(`%#Oo(Xl>?r4#7c; z;2S(UoM=`ZNL_GwTK4Odso#ld38eNXx2>I zjN!g#;IXSP73Hx#D$lg17P&*R+xc2q&fx8JCpA@vN#{)HN?%3^5;ErMD|345j~ge+ zn?oTyCR7^N#+F~(+qo_GC}LW=@tZsKcoVDbd{B;GHmikLcV*vW9vchZh~Z2ApcKY$ zm7vh;DRK(=Op)^eo*ruft>8HQ0Ue1{Y6wOqr@lxIu8(P^w10Z6zEQDl4MrLu;bm&r zQrT7=?c!dj768@%vA*uD9{JDYy%i5l2z(;t^_$eHYS;j!BqHlJ;+`8yQaXE6TNQ0) z9H|@R_N+{UKHTT{z*!yNh}~V{-~PyYScgWS>QB;}HalDu3`SywE5yGUve&yjZ%QBg zzN-UVl6#vHqrr?&wU&aui<7j@qyM@<+rw z)r@XxB}H*;29Y;%*FoeRH4>1w7prPk3m@6+n)SPvm1Biej#z*iS;904wH_tX?FF)W z)lU`X+Rq@t1HE^QDW4GGhWCoE!}qDVUIyIDUp4^mIaDvJbl(ZaJw60lN!J zeA13^<|x1H;g04i(4*Uyv$E78qfjMJYg*LnEyPyXX6&3 zPfl-IWqdCXJ0LT~g92hxlWj%BA}=BCgVT|6%nP{J*->;XsK(q*Wg?Bd-ymo~vuBNz zSS=}2yX_0Sf|$MEDtyF+q`?9LJiRg3zf7BB0reFOt(}@G93(WPw@U%K-a}S1p-gEl znpJ@JHc|Xc&4cQ4O1e4DyYrWPee38n=~%HsLM01d3c}NEB7t|pT-C_3$~Tvnr1UfH^j%R6$?Zj1W_&fAG+WpHOZUVaapg|! z#B1ojuE>>Z*_<V=Bh>vS{pL$=OrB~Lx-IV#LTB4tJ5X^(xbnbU#wru!h5Z#o$Bs3zW-jHdHu=22I;PKcN@At;IfCLUq%Z&kvfr1~+g_MPK zLrgJ@dGD3bgsLnDteeBv#9^Iip6CUR&z4I){F1ewjth5>w^&PO%oYBUS&l5!vETz8 z1y0ykJMtY{!SFML8bmSTRs>O-vYJq@lq1iw6)lH#ga zQxKfruz2zl{NlE|6LP+#u623%MRu8{=hX>++0B)_VOYFO5*3VQvWfHjOlQ*M8+s-^ zYC(K`K`uuRul}8P*&fDk=?$c~li1q5a~_HGFJ{*Led@T9oF9J5bU*d$&}^;)*Q2Nn z)j|>?y@a+;LAT(P=e42+n|3m9*u9*4*bfA0HagNuhSG}lApOalOuTGEoRSy6xl{^k zcHaFN*G3^+b08K;slRLiy4Kcl-ZanJu&p@CD>&WzKZiLTOwvOZ+@V&xQHtYDZEHKG zFg_f>7ttCvo>D0}zDU8a6w>e>rq(Xu_e_{U8~ENk3P6K_67w>_0Chys1}Yga$$XN^ z1(7jojWau3ML=@f|H(Hf!U&Kf$VTSTw^&$n05)xWbGR`T+0G8{8C0LWRH5UEb!sdk zKoeQW^2JEZij^<#;E&RlR$`oEB)Q(~N(Sh`{WzEu_Cbv9#z2GdU(JlP#N~7GTA728 zyeOLyYsa`YFe~O(PBqsq-J2~x*$C}u6#a|L$%Stvd4!~d*93X--DL|*nDpMO-_$WfZ&K*G{SyK{_~Bpq;3t1aEdL!W>8jmj}0 z!q0iwrIC?VzuefW%a~w-pa3nXwp3ZU*E71!a%Q>kmrSHBVmO>>3ul%j`Nb}=MDdqE z^HW-MjZ)UMgG1hL1$ML6s!Bl zMe}*0uS$BFzfE*S5U-(^Q$q76U0>%Wv1O$(kUzuw2J_;Gvh2~8qm+v-a*+pl$3psg zwrA2Azm+8Vju|&(r5W8^I|<80L9btm+bW0!IRYME{%_h~ljTrA81Wd8O~B_u>8zpa z%e78XKr!!hFtE`D)Ao;T-WQ@lwJxb(FI2IP!01LLQfD7-lIomguB~y!NKMo;Y=<0x zcXdFv*I908OUXfw==a3N_*Tyx<=P_iMZwkh(&)RR`VZ)Jb(ln;GS>S~Z7Ttmy}e&L zNtP82^53K`KtzAk@Iw!0+L0>7xYP{yzi- zD?Q9X@Gsxt>Q!H3`wTx5E`h}a$abjE^e4CQHv}ow1e+r*DfesX`dx#Pca~O8+OQDw zvZ}ye&CP0@<4rwEZM?uC!C#SZAvk?`Itzs(*O0_L_NyV7iaRfVx5qZ%IrNqEjXyW2 zp&?X$2m<#8Y*l8!x0tSn+ZK6zNR(j?$z)9oL~A}6hU z=h$lr!4_iJlykF3MbUJmaaVNP9U-`L>R}P`xOC&E)jbRW7<#R8NDTDnAWG;KL`Z=& zclR$d&yd=<=9zJSeF~g(6k~ftZ+8{{^3LTAf&2-IxP9?RZ>(5{21Bdr#Izek6)ryB z**xdA4A8t0Ikle$vcplhX%427Ged5czNXEJ=blvj7K^?OJ3yZZgkdVNz|6v?8kniv z@Y&l2C|J=t`YQ@L|1&lKcbb0JB^f2M*c+)()oK5QZjVdlw>unBu!Smm(A?89;_^7L zZ_sC9Ni%N~s(Klqb&|&rl#-wnfU0(~e;IW6Cg0OHwpkBro{ro)45o7sS zOp{q|p9m;`LGuhhk!&%>A`?EJohVz>x+TJ?hnw*ADK_of z4Cg{UC)0b*IJQ)khx!bqf?Sg&V`8Zs)C;uSF9BPXWGKM+fB<=_Z8mv*i`fP%dhcbl z!P0+}$IWjo^5PwD>punt$h7g6T;n7Vg1QL?pMRCVJwn?-4zHH-F}9?xBw1)<1f`%~ zen*6*E3l+e)8NdYpktdu{!6+}kdMh?MH#4Ek4t=})SEu5?u?a#;zQS%aJ>-cAyG5V zTIQ4qCsCft4*ao>p)-u@#N`BdpEFUTr$W`>X$zHa3<)!)bhs_nW&~*}!F$6>4uXS> z64CHJNz#hyn$}N)>_p#QOEn$9LukkQdcccvVg$oz ze6fE^Vx-8BiczZpxEeTHFb1|sL_nT_aJB8k1)UCg!wui%WgggDO%kK1&b<5 zlerF|73Jr`vA(U{_o@S$xd#q0 z>}KQj9&yBdORtRv&C&llg=Bg5kr0gf%S~JM*-^Iq%id;QlZCh&Ppl5nH%rgrHq3x8 zA=o{&&-_l3=FkRr-8Fww%K{4IP>j|K?$v@Z8-0DZ5PGAzI5 z84s5LroB8=a{S@?&bx0Fz#UxxWvI(DZiT_jv%uqyrxhGVrKs?d?btXE#Zq|Nz zcqZ&ow12E7GD9@Ijj&0M5u^$F2N&eb1Jx|Uill-6NIi7U@?HZiS8XsiZ2E}MgI^-{ zU4!fl7D=|kVkqOq8n2s!X%_$GQsqlR5;k60oLrlptyKk!c%Mi<0((E1&Ax6XK0=;x zxBOCj!t{EDHmjHb6}{Am7nT%buk0*Ve<-alg~X*+cB{7ToOxRt7_9hzOHdzgQkpbU z#k92Fzyw?eh*!|4w}#*NssFg0GtF_^^*+%E{Y1?vdzM+QGCiZZKx>?U=D_IwhVG_3x^*hs)^u=By0!^#LUA zYK&UTZk#=8bxJ=Li8FR@zWRp%I^n_%o$HwShZE-J zT3>Zw#n+};#?ynS%)VU@_bg$E`H;&P4Kch|p}JqSfDhH!o`jM0a|b{YC&G|qP$g6d z#c1}3(7?df<&!qu(R)I7+_*H9qOyD#t#1#8j{)1-uT0pAIx`RJsFa%ovATLb-BKty-Ag3 z^=R0<+~}thKXC0H9txCY*^uFZ1!AL)q@umPSfmWHQ?U0-9FPcu4E zOGlG_;+Pr5=y6p-odbu1mgxjIdGE|tvAkgQ$2r; zoWsmlOnMVPdw^jwpfLD?;AZ1RZwdiU#8Q9*1wDM+suvo2Rz4O{oVuUrC?lkUDHyFm;B`dt>^TW5H6-ZIxxMvGrC9GQZ?LGeVp|xniZQqyhZib zWU!idJ5mNE)$Fe{W`HBVF4f+Q{h;yIKJl?*OL;7(p(PBzv?tJ78=>87Q55Mf3A9`j zp1BGAaDE7&devZcZd`mty=im|DjWz|2-Qjc6S@VPEsP;;#_PpM+GP1-A-7-OPTVwt zb5|DwX(Sp2&&lndtl?Kb3Ii<8YW2F6C0kklM;WewL!@0i34b4M_rFmLkcV;&`N0j6 z0x+CsPERocrJu|Amhdi%^r99zWEmEp;(&Ul7hS~) ziT~Hy!o<^LK{hEyE9vh$e|X9?-3aTHyy?U7-!YTSbt|>bJQ!A+=$fGoE-C04Dtv8K z`Og-~Y7LTqSY)bIm5n!4EC)&H`Qc!VP~Za`EmsL+P+ZjPpzwhHi(c`bOyqHe__s3G zUpXi{V4jQpbbmX>_zi3NQvx;~zpAf**^|%@Cs?jpVOQ08^Q*kHLy!q>Fkt6c;Xkw|OmWg12lEg*P-E(A7;2|O6X`es-{=sh zzsaQ!`N_cHyZ?D6JCeHA6{$Yvth9&Adt~hT!n#m`;iZUHA9Ax+qE;~3Vw1xil z)#aQpHPedRhb7zh2Cp5x>PUf=r_H=LsFVm24X?dPoytuMR}!aKf;*U&SWR}!=Wr~Q zNlaZJe7&i#<0Rswn=OE!xcJX!2KU|lD2+v!h2Qb}i_Li+d2;t3HuTj)QD!Ua!7?T--R4XM56I=_t z%;e(8rzNLnXun~r`|!`5>AVf>>VSmHSFq)y0D{DA`!wSDe^%}K#>W4E25FiSWB-jX zxVO6>4l}sDn1i=A{co|;AlZE??R{#11iZ3I_$=)8@xGt-N&27I0i5Bzdk}hh;16%B zyBo568ZuprZ5(Kh?W;XVRfUm5sn$5}HMbn7U>Sy_#JJisB>Fk(g{bq={nz{zGNE(65gF{anOE1uePVk z59$ouSW9i!Dai;klLvDo(_0DB$rux$6! z4@}Fbw1i!OpCz4Xn}+=NgXJCdqw`@-P?9C|1?R>o>ua%P1NvveMH3x&-64Rd>8=PxBo&jc-hV*I_1l40zko)KW&;3tC5!UT5@G!w!adI+mxlgDHx^+U9Us~gd~BN>1upa0MyKr(%t5MZ6H5@) zye*|bG^hX@n19fe09caYw6J)P{)e=)E^qFtul`AEU;j{aPOa%H`CVC^G5#dLTO z-@Ft@dwGR(3K07Kn@qG%{j@2J7_`raiuWb75A+h};dtCRYW_QMEO*bFuOS*m5+PgA z|Hx5KhsiJRByVgahpo7`zK_uC`oZnr{*P;$q0W>SKG_Brs>D#SFd&diSGrKH?~mi) zUPy6R>lN8$xYPJF$KG!*U&wdS=jR zY0s(d{bp3OMh4nGf8c!yOm}{LDO~)c+xME-`7R_;cCPWyf2wy#+BcEPXB9_ovZsSL z+@uJkq{Q4q)hYD9s)^q@Fi-3sq@}ls5M>x(7kZei|jAUjSxdo+|T5K5)-Q%x)=?<2b`Eu5i0?I{3NM)W#!9x0QYUQ03gaqC6 z$}6(f4y98>pC-<5#KT?l*nsh0=Zg$Y8T1I^=NNUog8022xmJHt{c2aq`V;B?i{==E zUT#$l7KoNIH_QU^Y;W*toyV4JyB-y-tA2FCkH2UVRiQ?r%CrE9dq=)x0=F1OMWZ^h zFf|kHKyuzmvA{bx;L*3t4CJ)g^!#H&p{kFt!UT-odk4_eS-%W(Eu_vS{K~kLZ7s^S zLfNYWNx3-CQxkYS{MDn212MCua*#LvRRifHEqBKcS39y!z3j^7-y)553Db*Gqeb*H zAwQXk+S`(~=q@@&5>H_px5dUhEKi;IS^gpdQPz^Yc$qd939EtM%=GHTwYZb)D(D4K z!m`AbSUE0ia)Zz?gMNq%6u~ymEbEa;4-QD$&qEm_INGfa|LJf{#H&1C#5GxzYw!Y7 z6C`cz_&RV^Sz-Dz$-C7agEZtS79ky7PpX0p)JJFhNiv9>{Kf4UJSy$6Bxhhzsj}YJ zUs*%YPvXU#VN{>dZBhp>&v2BgYxEJ+xBc=?4x$eHQ}DJJV)ZS&&m1&Bh#SpEg>Uj) z1*c!nw|#0U@Sce|(z=9)ZU+{J4#lC3HDdyqsrqe*%4z=?+mf}LLo0U#3{eyOJs3?1 za#iNjGv|}4eDlqxnZZXF3O}FAOcWx%E@9G?k4@3;NUfxI=d~qI5u7qC=oO(>;VkEo z2hg^%Pp0S_$4&lrHksyfGT%t7moXhxxk2T`FqwUD^_ZarCH9Acim;zTvHdR3-S!^Z zN}hRsjiC#ttjiNuRLYspUJ3#w`$z6Awp7~^ki03aJ?4x5;)iJd4*Y!Ho}wZ57zuAe9CO4{YvW~(Q@$V(Z&9{lOx#Dv2-)69dmB$ShV3- z&1r;xx^Iz5h%x)<``O?^MVX0sP@imEz8IB=*xEqZ^ecf|?8jENwKqSOuyi+c9;ZTE zJu_;h^*TY_=3xc|`sX}i3WYT)Tw9(bd85n0sI(u}h|Fit7E`|a!{2^1n~z9-5UDpw zb<~f(xLkWWOP8ZmkAl?6Hp6ohVa%I+Wv*(Y@c}5tcZqp5OCs7lljSWnV#r5YI#aw7smZe9LZ2K=D#8q@txz z(U>#7wI{bSk6Skt_hIi7(#roGPqQ4!V#eE;)72iz(vDxz57qFcYAdHb-y!gu(7n~2 zSV?eY_t`9gr(D(M^b%#VcbW3 zQs5fQ(X%qHI@HFfN5{fJB7rE7_HvcnqJP9--%A!Pl&AdiM=}Bpf-5a`;BErBXsGI9 zaW?5Baf7ZhU*h<7rt?uFilqA+2e!pUo+YK<z)yp_b+M8bBN$bR_5ndBBk&>7L0 z;Zg=rF!8)mS%O*P_JQ3Ab-PB9m)@K@eBiO}da+I?IvSElkLm9TDH$y_(fvUE7T(fy z3$c*70=CVkiCcY28Z{p)etc|;AOc+`b&piG?eFfQ<7;Avu#(oSHE#G8j_V!D)z)$L z_UyCccdnJzHaTz)ce?gEfK`oPnj;Lhljaw0qp`MdpheRYFK~<&cpvp792a7(`7XHh zT~n9Up9dBItASg$^StI~`sfMUhKYaT^=nAb9@;=GYreJ0uAbWxG@WM3A)@+dyK>ZF zCu_LWxD|63+;fLMD`~=eEAwd-20E{-Wm|RtkpaN$fn7?6E>YHY*eib!{OqeeaWL-M#7q1n1lzd9{wp3rD}ley|D0=*Q1@X8sZMzIpgQZ^ z1grdvYG@7)nxcjwq*~z5Qk3q8cL3Vr z0^=eWUyz1|2{ODHeBi1eWXg)FRt2f8yy6CuI`!#USWgGHF^*^s#~0(%kqwX+^UDhB zFi@{Z3Z8^TL!haXY!ve0P63fP`i1FhWFfRz*y5p*=mK9nAqUzkW=dENZ71=MudZDM z#ltzMN{ckGHb=Rqn^D>bgV-Fdp$19KP8JcL9sTyF4dW*&=q{k_%%(0sT|5!05ToUG zD_6R{fV{nI+(EC<+n#t_HJ(RSS}8U65`_mAXhr)^5a7-Z`8M;u{>GB<6wXFMnZj`5raMm@ zwY(bpuy0N2b)w763FX8QGLc zD_(r_Qdb3u-6Wp(7ZM>ctf{ZVj{6_=+RdNP_z3Zs$0o@6Jz7&uza(N zqVIP#V{k8UBB<_;^)}Xqcosg$)Ww;37SBFF=1yDxlC8D3h3|ZQ$mZ2G#J?5mOLjr8B|FWRKEQNdTDV zDQo#^+rQ*tjm(&8`d=tE>Xfr0(74O6{4VqdNPJ|hUB2Rz3VfT1W&=h)lQLPB2qS;- z9j&X0-g@G0`*f5ZVteZRN>_`ODB(0Cf7u7)Kb9KW=%{gnqxTf0XY1v13&_^Pr^^)! z%))UFjNWnK8w9RE;F0#bRzP+EJ`)V~dSw9#I!%|Gf!BZaK^WwFx+w|eHYcB-n|pLT zS@xrIQ`>_2{52bO_F$2Y9E4{2_d&P{KyLVIeIcMzTep{w3_Gh|SN!j~0wvTKye<<1 zZv+R7o}g+qzhY2*pTV-XpGU|4!c>29-BG>xcwaFCcMfozz~>fPFBac+@E+Sbl&BuR zJxKgL87+DBArf`{vq(Jy`?uwx5RC2}2G`b$o92n2zJ7`>cY=R-R57g=K9kiJ)(DWs ziTboO@o&3LZR-=*Ue)f_>E;O;I^=aR0%ON|8t|W%mE79e`c<@z2n9Z!!~2}45h#Xo zU5tip#rq?m7~c9yKO7eh{Fj1k>?zCx0+h^DT483-Xkp^mcGvIsX;p)gJq?v}l%jO$ z5a>dd8*G%6E!mVHC=ZJih=J4P>h z_IRFA^PEbUO$FN&{BtCB6ijp#3~>;Ktw|loGn!P{Q>Y+av&0Wrkc3rzvZX13EvX=; z<|*y4vmC=y6;x7Wq6AIx6slP&p02BTV_u<(9hLJSm3J%gzcVv`owL_Oa9RxI;Jnw# zguegwQTtq*fmyE006WkRsZWRPM~GPc)?DYIi>One`gRRJl^;Ga7haar^tKiLNXJql zX?`H$Wo2Gh0CO@CaWg_5k2=6h9a0OXVW>JscM4&mhMmB1G6DOkt;%=_?cTqWqc#3Zc$KhH z;CEkxhJI;N)s+Gm@+(%yS8Z7vuR?N1WCMWn;?(n&=B>gxLWb{BgYEsH(=7IG+STnR zX&&IV`EE{i0FNX$NUOpCuGn@-Wc~0NllF$k`F8u9PM)23d)9F@DA-{sBdLAS8}#eT zte(iPCEyerX%adR<$UB-0b$&8^sRPVUA*^h*MZFv%=`QK5-gJxO9IeF_6U!+3?Q0o zgnr?J(uhHF)R`-Pa;PXdU27*?tbuWw!1-@U}7CBETIZ(PXgj z1*91Q^l&e%v`VSyo$4(>xEC6%NL`3SURnDfdc8n7fqIdAwGnW$?ZK>yaY9a$QI2{Wh2^ikWLo%m*Zw5ZYHnPNyfF|4_Tp9 ztzYQrd%3!4W5hCr4(0E6-I6T_C{8OR^gT&Yocl7( z6r^vBto6_xsme__Ipv`Dh<_r<80!nC*1yD>iL?pdEko|fGYFUf)Jc@{ zimRqNPW|xHhG`QJUk_R1ZkPZ_$M9>EMqen@96zBuhv8}+h$TkZ!M|dj-Neun9m-VB-PlH`+ zRabnw>GB!vklTU`R0}wMgLBOh^1J7I%~a}Ee{54=5bU|GixY_`MZC&h0B z5SilW`lp=jUFEsic)BD875>j;d||%E-+U@)lE*&LVZZ~+(I6fad53k-?)YjzBisFh z0b1@HNYT)nG6@VB0JVR!KjQ@tX2s`ta{NvT(?Wc- zK-Bu3uHF3muU^#z4D=urtKDzjAq`ihb$gK2#W*)F$sY+h)udI0?ELly0kQ?w`ys7U zx&+wiYyg;2$?jkwHXWtR&iQc;Ma?~joaa49p0jOMpe!|Wd6%=L_L-Dsyxfez(uZ(q ze~Mxd<(U=F2}dImgd}#Mn3`l z-=jEcYmXaDKaKmw&a6-?fbhgHU^z^LM|HYqV1R&l* zdI+{wnJ-2+iUKU4HC|^#hO4Z3J)}Y$=yGNj`aay9?gI;}UjV8%cFG(y=9f4LBmw^X%;N$j%KLe))bVb~U4&*miy8{1R{r8$txA<>-p?G@Y_$oH{bAkAQ*1Fh)D zjLf6NTyGg@0Pz$B-3zb?fRROPadX-K@*~)&W8DwqMr`l+mlp)c5J7-8j(ebXEI&D zO#yAY426H3567RW_;w;|DQ~XIEA)Jt0NLXMkzaxdZ7NJFQpdT3zZJRFXEVafjoc&7U&QIcs{%;PG^Qocgr@%{JI(`_ z)TNGCmv&CsO;bGaJ*?tM;gc(ln!>UwbO?Rg#{v15gkRa9T2q^|0!*Axr5CpQ^$f}` z@}+i6kk+;PvlV`=;nkS}MaKl-TR|Y>SbHX}u$*&kZ5koJDLdf2YgeJgHv&!=u6*33 zzRQ*a^fqj_$t8(K{rp>-k=M1i@!Dxz)n;UxKdL-U(ULHNCTYR1C_lZUpR#J4YrZe> z;TuiAB(|fv2v-*FzEDVDC%9%?xtaT|Mv$&V205rZ+b05pQtkF_@~(*sT7EcrAk^(M zP{aAk%5nGPA8&_Gw((!~0XkTLpgw-tHfsL3ZI-Q=4J=!SORy_y@B`=0($S39SG5By zz~HC2J!#x1B7|nn>)S#%UbNBVIF)q!QK%50Q6Km5}02xoY%h? zhStZ+ZvE!r+i{PdzJ{>Kcd;l58&o2k^Q< zK3G`$eS%#XxaD86p*X~~%dT7A@Gc1O);#*3!>;twm>Ga?IRP1}d4mSaPj&lsTG4Az z=OJk=7tn@;Db`jnn|?Uway5S|3Dfom+P=6wez5)LywLj}emM~XOLU>v{A z10PF&?W!8OYT7F5t^L?8099KcN3-jRQXb8`p7TaQlX zKL*;5I#DZ%@A=E0unn;ZB8p-N93|8z&v9*0a?g=mVL3OQl(6TO^VCMR^GIHuqdJ&_ z<#Co-C+0=6yq56a0m?9vByZRLJb24r@0x+0K;eYY@J+@1HO_ulLA*2-2$$T)j}Id! z5odpPD7%7g!GWm>`y;m&SQ*Ne;2RRFRo`PGifUt)tmGfX1zp&nobDj4vhF%o^garC ziT?YI8BJNG;w)eMcWI2!nDVU$PmL%^cGX0PekGHB?Rf_gKpm{Ym(al$18pxqi{WLu(@yW%m9}F^sjz0!VtSow zRawUAdIONmTk2n|PGmDG`fdUFylI`^RQY+ac*Y^7&I6oDd-7Kkm{_aarW2cwn1 z*mjKze;27g^=Q{|Fj%qF+xGsNik<&Rkax;t8o{jTT0?#xvu@O@LVl56w3UbTDj(HiqB@7qB7*hbWY}TqUgX;ftA0Yv-2VSj zVDdXrlVS%P)|A_nzMPsogAOUw&Z{j>P4->7w0!xql)%Xj*U2~YU(Bc}ZLbqAC=NuP zOyNzoF&?qj3MG`K1GRp8I*D z--_9Xk|Jq5fN%+K>~idF&0a6-Wh*}>rbk?p$YCcgJPlRSZeKaB>6r=1vF7^eX4EpW z8%p+}tI2yqr>mYb(f8cPNoP!#D-JJorDjPNjm_rM1!wykmpHC?R6*)E?*;4w9b%SH z!tf3p4y1z9_a*5*`;FuC}Z>aMAh2KxD=>_-pT@wN2WSp~kbh+2U$)H6ox#EF}q(NH$$H%2c zSLmM#CrPM=M&Pflq?aX?UkC>ipM8ePNv^2U%#+2qsQ$pQZ1h;3+&IE=RIr`ok_o#M z{c8tua1U(hRqpl}2iQ=ieUZB|K*9Dmp}E9YW1+lEo|T3fUB~_8C%HPRG)(P4t5Xoo z@$Qy$a}nRjO~^itV!03Hahm{JN_$Gz$6e5tryjv%7U^;@K|SslxT=bV%|gbiuSOlZ zwj;acRab4XjK778jsY)y0n-dFXKNAxvHw%gXnlem?+*g{m?S-7Omm~WmFQ|{kwTS7 zhO*~-Q3RR;;>7yX6)otlBKQstHY!!)?Fk#gJGG@XqoObP`cC0siN)_3b&oiWXDPWK zBgIz0R@m21=4`EMDttW!fpqf>n2&EJoehL5;}5bsLY~0c*I^~J?K=q7&J^TYR8>Oq zog_ilfEwr_JajqqZ{G~;CR3BUY{xud zUL5(SzWLNfZ70_P3kGXP@#7ZLp~Q^CQS6*Hb5!#DIez(6$uuQ-`3?F~&?YO$T*r!j zC*C=rs^QlKI!)B*T)8ENR4oJ{KF*P+JqP2GKzMPV6T(^FKGh(;Eq3Bl;1!MBNB+& zCQjQte(d_jg?4TAF!iCgJ8(BiE1@P)Adah#9xL&H0yRCVa*Yt=s1|_g66dN1n$BL& z^ARn({N%!BPtV%VfBv(4sa%r_&cA$S76;3UaI&;!(q_l%#o2B>zKp25A=uyJzfv^q zTe-Hs{e)woU8W{VVNLoq@p2B486LER;i1MPx>M3Y%N0f?Er;kUGNUt0bm+I?QO!S& zc$B+vHw~^KabqX3LqOBjeV4gWI78Ov?4v7Z-B-8MwqEeG3)OqwR_=Cuc{ea`a&y^7 zb=-z($OHNk&N4l-TU*(N!U>wz@>S*(P|!7&UGKZ)1|{Gj^=1|dekVI&2>&8DpyN*@ z@J7mapXmEdx+mYy0rz#s{L-hJ<}6PN7%tMD9J32A=(pdi`>8YLd*Sj- z;ZxGHWQJeL`5%s=tvF1Wz)*?=(2T~choeVeF)j%&pLFg~Y94`F845&8j5|?MzLLP! zllx=+lE6s+_fIS$;cQLujHw1{@0gY|J1Tx<2v z$5xQgE@-v8RTMyES2%g z3ZY5+kosjbVxF3@aIhob&{}4w&kpOz{K1KoDPEtlf9s8f6c1#%PpBH>F3VxQR0K#I z!{QzKCkk@wPXg!{QNirPbT!reRV2KTh3WyP^bKWL7tbw72Z{S^N;v!}GInijx#${VZ7L(t4)I*>hLLCl~)5b;aqlbrvz;^ z&Y3yS>+Bddrd5&IJZS$nE^6dFpuS>l3JN4*_1hk{dz{4BI3U}ZM@-Vkj@RiYs|pdC zq%Q32iVY1Fo7f!mOA|+;VJd^UnTx3bHy=YZHLDK^WYD3{6qI3Y(Vu@xXJH&Y6r{Ln zTiV&@AG4k(CVV+tQS~kLW#=7J+xWou#k9Rc0dHg^qs>D?A{p>&S8q2hFM90MJb#9E z{1+Q^D*C>tUR>6kXGdYNKRcoUXhm!3Wl_u^t2!;eY<9Y|6tvqLmk+rx@hw@Ib+6tr zbcQEEPFa5SGEK3moDuWAN?#3F^u^+G*u^LK<*`@tD05pZoq z$p86`an%MmV1|06HHCaJIN|QfG(gXD5Lb~WcA2b&){%2(+iqyJ!0X_E((Y^c5-2o_ zX{J*lTOaq0nrRahS8v`9f+)z`$$}`&C$#3~AVLt|zWTqx2gt7RiP(NC9W(O)z64|a@_mpqGB;{rp-Ny?A+5?;~eh!L|&KkUfLLpvaKx=B5%oNUOHsrzBgZ$wOpmOOoHAJz~9^n*y=kAZ4K|BoAW-N#y-~SfNO6UWYN66q3n_b;Lq3D8wG&-^ zT*k2Pqfls1&ej`fG?dU!9Tju}D>521+OJ0gK`J7sj%kKuw`I%FH^?(jO0WMqBUSCW zGu$+!!NJ%>2&%wNqGM>6qR>R1*$Z_n=1Ty|LYwqB(_$mQT*Lb3I;2T?_~cp$K}Bd? z@={N@h0p8E-wSq`;=%%lxM(3}W2KcYo|G%$!E%7u=599AZmn4@n_2GF6qnkV41N5$ z?lQT%*+lR?5fD3kELDSza3x`Z>WI2n%go52|si5%cXF~LX1(iUnraAfPS1xw`i(?^xtv*_qw+;nQ51Wu1m zmS*+!LYmrPRT>dKCPC*5a8EMEoFt|dAX5l9&{;N{$%>Zb?^+a}sXM}d3p;;V{_Gut zD`)8x#+QYO&VaDRJ!0X!^kx#Q;)p8*TObwDk|OY_m`)R-b5!#XI&wjWjb*PYCIoH) zwn~FpxLpUXzZA?rFnx-tz-vL;?pq71U}T;(#Z}+PlR1n+g?qO%s(=SlZgU0GirP_F zGhI;KwK^Pa`FJ+NB{{B0kCBsdqW+tNVaDWyN!>e|Dm`MO$Xz|dL0Ip{Y=YuY(Pg*% z5(2O7XPZsmW69}WwpWQ-1KI}$l=icuzehezedqNAAUD!=P4hNv3mo^dI0)FAEt7Rs zR#hnq?azTgiHgi66nDSbbR8PiOkIsK}ZM{RcbT zEP9!V&wPx`N-}~}Eb12;sVEva3^7c8q&WER%B$M5%JK2)th%gcx9KM$8$XX6(S`Xy z^CGyC4OE;AuWPT1o*99-Pu}gfWj%*|FH%$ecQh)DZcIf2wA*ONf_!|Gj73b3)q6V+ zT)*`0-bC?-NSrz}!3rYGUZet2%;H+#RcLG!`UVrK7U%6Y&L{5_(fPXVzp5z?#Aplz zFHdSe2u8V$P>CsO5KSVly@vgMv8JWDrUdu2R&9I$`75Ot7Nw2q|2vmjl zUYcx+r;UjUKDqVE4vDMBd`hlX17&o!;*4&MZ*rrSM}D1QQyjO~nfgt71`d&mGIc1+ z&^9YF5po8{X|RP%6xE=7FQx^1{utxbZ2a`d6}sd*8*bmtMkRJQk;YhDL7SO<&SSf(j75jQp|*Enaar^hkGbg`+zw> z0P2fUNi*T=8gZ#Nc-`%VSHoErKK-+2W9xst>E3`n;@8A7yQh3jv~uB zR&$8QbS=B#H_?cXyxlzmhkUKk_c>5(f#h*6(oDwZScC8 zt;CiG&>(vo&dOCwwKX3kAH9*QBk5DdG&8q^^}5`!RJLERDb`r;{F;J=ojtMY%QEoP zrixu&MHAAA6vSOEyF|6a5psc&HQ&@fQ#lMlPoGw5nSvPf?8mdPd%>IE-fC^9#~_*Z zp4>Ky;h(cVP@;`c!15znE6qE;#AO6L@Mm?Z6qXYiBX5#TYd7 z!QTezgfy8ZX|7s=`S;uGc4gNRJL!YJBbNm#E8Y_&3YkqcRie7mT))qZrT1M6(3yBC z($%5Hc}pmo##by{!2h-yH1$jFo2G&)7g1t8q5o6cKS1ztxyylV?j}HzBZ`z-{qG~$ zw#6}0II)0Xl&uhb6ik1+B4viRM(-^{*3B6e$$+TNI_yGGKd{AbNmestV$fV_5SW&TTzG4 zDkwK#c;P6%!-)5dyy4lT;8R};PXV-0V$?=u*@AT$6X_+gR&oPcLt-j^)Hjgx2L5Pp;vr5RzI(0l?Fni-1l>iY zT@PP7cLoHcMy$wh9%U}WnOtc01xdCqsp`vA@RB7jDPv4<-KhOJ`H-rMmWA>O1)RZw zdT4mMnm3fqJ~Z(k(iZ$(Yn4nXhUCk=atXMT-VVf)P8dB z(2{xH|JaSO*gbt;J`Q%A80zXU*LvciLkERQgBh+}Q}X&&kKv(CHv^n^hf@TsZ8piA zTKMT`L`Wo3hA!2ptZU3hot3oiT_%&h0s^lCK%X4e?=<|r^FWZ?ck^C(g7<>~&?`=z z(F5ZKLnGt(a;X^W$nVzhI#a8YJ` zIj|sg%~P$0Y;B*@z{GphMdh`Udeck_M;uK8<>3~DQKt6of=5@tce1Z2e~v!ONsR2H3?($yA(halv;BkXU8 z7#I`f;~-dY#!m^GAFXv>t^ah|EHyQgccW?8Pgd}j%nMNDZSK0Jj7E3**@!fd=Fw$Y zwUSIhch&F8N=4T!lQ?+oqnS9>JZB2t*%;BBnd@X@I_F6r?YPZxrkkY}wxr_L!`0+j zg>zCJT49VY_W@L-)bWds6i_adq0eQ>(I{HDsSQ6}`D0{0%YR;?CY*>*1m=u_DWCu{ z%naHpVpTj}SeShKFY|iez1xNu#jE({B<~4 zz~cDppAw-p8CuC|gd#I8__*B<*!~%K$B9L)T=J1^I4V1?06GLtD()0FW=u+Pyr(U1 z`Y%wibQywt5kXO*asq<98t>e6FvKNdDjBKUUZY2_dE;6m(`}w*%1#Ed%E=p4WoeqZ zK9r&VKc}a@x zTp``+UsSD7dmy=VduG%pZ4rYJ6C0vIAmAIO@#geOU^Dss_5>_olwG6!OM)7zsIY?< zdV*D~&^ckRJC1d@U%<9pqOR3hrXjgX3w}Cuup9*mF`9XQL+hzSbKh)>e3q}g$0|_e zBMufLwnt`r6G>ZjNpEcWRW8uS7Tm`8SEAb=dgxN)8Vi!QOVpUYg74OQG3N7hbDn#T zg?@~BhZ@oruPfBvWb}p+o9#;j?|j7KtVr#y4zF+brPUQQ(|GD4b z1@R?D-;Hp$9 znSU6`Il*F3Pv+YUR|mDdn>hoP@@pq6-Z2NF72AzNipTVHg4;Rq*RfLPv_=h%y7Ym% zbMliC>~1O4RkB-I$}=p7(i5q9FEt(=#hP|HBkstz$L)og%gH&W{<$&~UdjpKSd<2Q z4F^*7ESoL!sd`q7s{Qv)rMVW~A&J(h^rC$__3j-eqn87rd%AIa71efCcF<4%&?(L4 z&9fFy1BBKmtW_USWK#G#hKS1Z{OapOs}|LSP| ze%cu`xVtgpGa9#`WTsywq)m+&L5YQP?ot(Y>dCBr&&FF$51fM=!aa|qs#fd8uhl{k zWd+!28-&~ch>iPK6!su)G9C_Fk4^i!GE;@CGN6AVfJ=9)YUQonyV@x0nMR|lUnvKJ zJj}bY&?nN7Qcd~#j3=tunfo-lV#{p8sw}Kofra_Q{p38B8)vUuc+8dqmLlI=F;k6_ zRQ5gI^OlS|_J9PeIw~Q#?vS!zIvK)Z``kY_FsTwy&?c5!1NJAlEi=aQh>iFHLL8V5 z^MBU7N%j`HWgchKAx#^yVE3R{v!|ke)c9^I7>zn0^Db+*{t6wn;b4$VhpmX-aVGsR z3lD8n9u+k)i&T`%B^w-*5Y4uv45S)Lx2%*#-;G{VMQX#F2mu{|9!k%C=?p$%FVL1> zY2ZJ9ym);Q`?Yu^XFKv->7b$xNAR6c=)Sd*HgZL2^j5atc{wU0P-+tj88V%xHfZ9u z8JA`(Y$2MO>}OCKG7N{zB;3RfHwA}-PG+Ih-@;r8P9veMolN_%x zc_m_fH|f7SAN=aTKFz8WU!#`pF|YH={9JxC+%ANk#{II&U8p-2ke{%bpl0*ajS@+< zfI_~f%er&YeJ>`<;56Q)nTt}y_bj9=_0RP5bP}liOQt%msv*Hrf!Il}Gmm?)S#h8Y z#tT_GX_EoBv>1~DTH2*@zw}UjA3Y>gQnf5Ci>XQOtR!*rwSo34qqDH}k~Ue3M*BL> zS9f63=g5n?r10mKRL@4~eapWZ5alvC!dD;hnLDJdAN4m}6cqEBX4y02 zu~+(4(TXF(4b~reAi1VvXl!OGSzxc0_KJ6o_M-*UM>9MXKX5jvlPb*Xh=dTA=v11~ z?*B$DOG|a=D(arQT8zBvX!{YaC%4EE(BBbv^*z(cvnrIt(45;{vg@S+qq&^9({g16vFEkF5M?6;}ADb|jBD?xpXhCX`l;Adv9U#y;>s4&5T zT6RQGhG(k!F3!aKSk&ZS@c{9^Ak63JRT+JwvU8WbMC;VMyD};dtFo0|Pt8N7rB}%z zNN-V@Vo&|0*SAzh z#q6t@E!_s0d1#|qJe<0T<>X>V<&*bE)!%rs4KQPFCKJ?%343ys)@6VjwdJg1! zTqS`ucr){RjD0DK}-j0mY{!bWD@_Y(} z(O)6gW$lHD-f-^Bu|>^TH6Y*Gq&nV2O7J{|L?Em|OWp88@Ru5>T(8^8L4XyMriO*= zfx@2b5`y4^S-X0(*gkwGG^}@6*3@7^-Q$?2WJvo(s+G85Mk7nYO)f+$N=jZqZKjw1 zEaRP4y1w@(aPZhSr{SA_gs!rUId5URTw%-q5lQ{B{m^Z;q?go}Q$j!P9AeBLtNj7$ zC8bVckbV;?^K2G;=a`w;3!2wF;E>Mu)nAjs7TtPlqW9vM+e$9q@b|9@Xs?wOyQLRhjZTd3Y?dRyNuO0#T#4uiUX8>`vxerxXP9)yS5l`TA@Q zf}Ca`rvLdDP8Q+^N07UiYe+r7hVzU&RTE1;Y2xx{sc+x#N4div1nEugQqPG>KM%vz zjfy5}EPzVCa!ZRrW)ucKsltBOcyfxDgZYh>h4JGBxiTQ{=-d`=AtaL41Ws8ivFg=0 z3tr7Gg`Um#EMvCoH|Ri52Q_>ZK8^CGl^%7bGO0-*FHu$_t3#X=ZK`H@uV4^M!YGvd zLaA_LGU8aNzm$CB-Deiiw{Px_T*{0yp*0l&>KW1ASvP@5wwyA<*j1>Z#dNkkhl=+f zmub$AeX=+j_dG#!XT=8Z+w`wjtl>j}N$bj@sI#lkD^{E0dp)iN{Rao0ZN2i)d%i5s zldJT(Ddvf$OmEc;@0LwYhczvN{O(%gYAlHCRFP(=#N=L0E*~|q2;W2LJ-GKx#?Kcw zXYvXFVwASz3U-wcyirGg_c8otuTRhMAZkB)uwY(mdeSt+M9uZ`}~ zWXX+{yI1_c!lXrfIOmbZ*~l-@NZKFc(wb zlnb74;jQ!LWfxB1H&r12sij?xFwac}Otg_%e$bF$N{8;Lx1y3wlDP&GeCx#c|Bah5 z+Sfc;v6QXyKT8XZIrNkLT_u1yne6O#^k|JLHOI5XAeGIQ3pqtm_f`lHJ`M+Y2h?Y{ zb~V@y9Glb?PRZR%^L=$$ zVaAFFyu2vbhw-TSb;J;WFP$fTFL&|doFUaShd)z;SFP~lTnLzpF+%BI`(>vBfVtdT zd$JUy-Lv)s-9a>Ic_I@P<Z$FNZZZ?ay{efkO_B#|iHF54 z6q;9fL*upaHa~JviYSQyOi~A%)Cg-(i%_Y;0?7R5?Uf~>YDt;hf*}ZxGGrZ^g3i*a%(CV#<tq_=EV-!0p|DAVM?SThf9Fd$D!ngtoYWS_!DXV3M z(yWMB_r5rXbGNQv?t-I(0|>yR8PMbFM+~>oI9yZ`@q!F0@LH;$$~Xw$zR*zLvSGgG z1W-HmQKN=Rb;S$Tbg)g&jabbqWRW9Qi_DqM@~}XmNle*-^P)tQPexLP2`bxlZ)G=j1njLf4J9`D{dM*fJYTrzjij@;*r>Ph5?@WB1nYmM@YxBa z>pa$uBV2;nBg6WQHqeXh~s{g({MZb$Vk=9M1hs-c>HLwQU}D z^-b0ZcFG7*6FuSN6efPrfQ8$UCM>9lqLZa?kDS6(6NWVarUKnrtdAJt=Gs$J${OcM8I&|JKEOI}O zd@-@eK~o~FNlwIyi(K@wE5^I3PI}KT+x{2c*QeQaoWW539V@ovhurrEJ`{lg`NiDu zcJ5Pe@98_YM0eiXGgIIS+2C?nf6UCv_7o4iG_|JiXXX9}U&5l~?&&WCsy5hu&jG+T z$rio;K8MeiynD@F9%*bA;XtM^Sa6}43ErE299bv(A6UF6c3HdbpaJ=qI_83S|J-_n z6BK)i^B6P8gGbh(3(5yg7>?BKW9VaiBkBeyK2M6p^sG>s`F-X8*Z8Cv-`b=HV`=&S zn0l+Yr~?z%H~v^i&^UY$|>EA#1CFMq;gU@ z)@hiyee4rqfzr{D);eLf)3%^|6)i(Y^}n4ACq2#H$?=1%hBv;f9t=87q8WjVz@%Ty zaDV68AM+YMe?Q0TLZ_C&E|bVpGwa!bw?Fe`kkep8vd?oW!m@pIBj|N4aut8ZM_GS% zRkZ2k;4paBl^oBC(=^n>Rr_pAuWs0Mxi+8IRU$9jZ+|9j%M;49)x^zu`R8w&jDsk$ z2Vjz0KJ*frqdhG$+U2!6iQN%C;~97DIdE0<>3-J+r!{OxhrooG3jbfoHq}ecb#sx5kBZy^h-9 z&c#EPgGRiK!mA~PD=%X~N%=wbQ1!rDsr4q)BP!I)yGJP(-HMQZr_^V$} zHdz=(v7Z(Zq1s(eOLFYeDvQMH?o>5KWG!m+^N!mfwCbazN6`W0@d_-SGN(m}be0wv zLjU$r1|!&=wD*Tjvr`7xW!rerSK+a2g?&g3%UIF@NG0w?c^ZnA{`lTBFz;o9&L`f1 zbiMKv1^gd{tdy-aSVrsDu4Zf}IHkmy<9SS7E}{(Sp8tI}tTi@{F_6NB-6*V_(o>Vp zIL^jtALtduR7yi}HkO18r)<127Ak(Y5UlM!|F6h_*)Pz=Fp^{Yai&_ z2d=1D=aal&3-zr)fvh^yMR8xk#gegP_kH8Re;XX<3RWkRcmgCbXslt^<}T`o`7SD8 z&Yv-8EHBmo=(pG`j;mstdlQt>OK+|us8A^aL5vlxJO2(jZJt+hjMLL{UR9Aj+1&4!*KodF@9k`2>Q3vgSn0Cz z@z>?B2$I-mTyZH%&WpS2YIt%Kj5&4eLUO$b2LuQS;g*is%~xOClH7W1Rz|T`MK-k# znKD&+Li6wbEi9Qjf0XO{(An-X9x(G$gI2Qcmpz5cV?ctCD|$T(e+v4?H??(t6_?h= zjLu%H`O3d_ZLskOh=ByENX~l*X+Qs+_afN#6=yyy8TN9mEyDyyo9e4<{rGl{S#F9b zKZvWqjAd5jZn0_f4<+TY0T(1BBlwGQ$mZBW+(mR+@0L!_HLVjykhF()u1n|{Ss zbUC{@KWkbfH6r%NO7mE?@Kugz-*yB)5_LI*xvWoqW35FMKb&K0l!mdSD zvgmUbF;tE8hnuEY>7pI0tdjrqZgS^jtZBEYf0wG$DDHxopiSKGee<4qbn<%UPHhIga zv{=hXi72=y<_3;aEOKf^dd>@3s)+fG4C*bUw$lSed?XyuYn69hCc0@xBH`}~m3^gL*tVkjOaAjU{m*qJ zv}r^@(G)8*k`z4oOsVLYmWWiNNv&UUQ-kO1&5-6KFV;yK3zcRy{s*OI)-YM~dpo7) zUHvO@;3`0z|7iP%Zmkzh-x4hT3gkd?m+24|qgET2U@4l`V;-`R2DRFw+;+)S=cdH~(R1V1&xze5Rw zDW6i!YknbK_^h#`T~cAR6Xb~(TSWUeNDNxRF0(pse+agyz4TlET7L(fB@J!r7dW>( zbJYvUd*w#_0J9Gz@!Kqm8JKj&>NmrdjkxQ9;5RvQ>Ei}0nW*wU;G3xOM76{8jDAikj@ygh$M;c~v9Ifm!V6^7Ubdk5(PApm8=mlk z#=WA;)XJiK`@Dla<)XbX<%r33e~F60U>#0F#h+^M`diI%_K#99%W*{`NT#Eo%dOR*%<8L(4yo8B4@km5e@jtHNPm&Af>s(gS-#~Z zXfTq_?G#kj>Re~bP!ydW71+?GaEf0)<=SuWYVTCN5-h=)$gB3PwAU>FK=}hIaA09> z;_b?lTEzgIye=YeLcDdy;dju8WGBhd0O@CK=LujIgjR2iegUtoGS7TPV*8Wx*&INjA zAMxUr=HpYwY{e9yPiQJOnMx^H@=QhORW}&0P_a*m1nA}7RPbR+Mpc#E>@QfZR6LZ} zyV4P?;nEd?uBRjXdNg`oSF|s%*4HmW-nOz4VYU^_X4D5eFeNz z*c-{2a6xe!J8{tg93WmD-c-&-1^q66M<#e>t$^8X{{Bknt;rhYY;&y9wbCbqXiI_7 z`J`9=GoeYHV)f#01+pxn&Ed;PpMTreowv{{&qD3@GmRC9$gtAzP+l7hB`0yA;ev9p z)Q@;gp`=O@?F+@c-(7hM&M?qb(|^7{cA?m)VbP26vJ@w4nau`5^Xk;UB|Q>7Fl_1v zer?1{N^w{BSM$XygM3|fFFXs7xo9i=WoLk&YYxZnc$bJKP9;7`Rhbc7@qOBeBTvsU z<9pw^INuNU?z-yZF`!@oU7DH7c=#)??j4}>*Ag3c$HcT63iWDFl8Dt0Sn|JJHeaHb z-h2y+rOeiWgxDN(u5yvC5T!EucP-o?o;vQIvphA;SAs%a8FLqVuyZ>e72}`d5if(= z174q#Z%A`w2fUU3-WNYD!ro(i2{Qn6IF|4qKV@50>eb}P3t$4VN;ojigTA*>E0J@P z#qRko;Xw_!lM&zVd3}GvCW-K2bJXZCSTAx7UHDKGiE1$Ak zI`Z*k@usys@y!j7w_qW{EZKQ5(*08=n5O3`;yrTV`Pnf=@qyG6vc8<%l(-D%INK~fJ*)B?K%P6FS-$)_(E%g@a^V$_J{-qFS+YElVJ4pb!X+ppj;u30xelJK^(z9}+?zH$koBCRQzIU|AmXTS zt?7Ui?J4Kx&#KghT-E?`FKUeNPK8KQ&?b>w=c7AC2K9&D6P#pB5B2!r(Xv-i`o02$ z1b+iRivAGhu1X*C>CawJ!C88b;+2G@|A_9cGDYh&Q>ngfS*azu_*|r%G2Jz>W0=Ul z0A|(<5qg(BI-jbB^C@l+Eg_h5jaavAPMf7v(^@4%T#ER|L=?@9i%HTC7>-1;J+z|lB@rW@o~nX8l{z z%}))mMD7BkAMKrkSANmzvVHE0&War}7X52!6~5(!Il0X$P2MQwfao=^+4sY{k*V}==Op1B3y zXW#Z+2wdc@s|{sq)lYNqZEGouxs7EqCCl^vNxjM_gxS$eeBJ<jZAC=Zer{-*m0_v-vRhcwtJ6sUR%!EU`y;@uJxl7D3cxsX zG~ie)QOE}2DOaf5+W zY#2x%3gKtTPAmOzK{yTO(~7Aj?y(3@$Ef4yvl*AQ{&N&J7(vaJX)@8Z0r*g>5Hj^Y%(oysJB`N>waZum_MC4D5?j@%MeP zh8A&b3YO@4$K`SS9{HASJEi&t;~ZlPjM%BYvA(`$+wvEnU;s%%j(#nG1(f2q3FMV$ z5cW4h{k+)q3%_dm3olNeL|GJLR`0mdbj$uT-Rx5P@|gW%nx*;XM_+@bOz~x|D_+Yw z^E}b&Q*e)5?x%_@H&#IkSh3qDQVr`}zu;Uginsb_O+y0aS~i(@VRPYQIkH!$gq{$# z2bDFfldkul)0X+4nj1jBRG_MjYiW=;0D6$UKW@Yj!Hk1KGrjxG)Nv`(v-QACKv!$S z%@3qG4BI;-h$fKYmX^`as?2V%DeEDJnB6L>-Y1I4iELq9*dxo8$STjO*tNy+kIDCmkcyU&}AFE z@70f_zjY720mf83&DbV90gNt!mUOV`T3gF>`zxH=pUx|{b3mKUeN;z#$6!|r*n4bO zLU*~@H6xj5`Q3?Q;Ao~T8c3E_o8g4)l-~jv<|H%6XA?#h=!kai)*AhNceLt&YzGb* zbqsL*pHYV_^^gij7TpB=E1<~NGt zoxmI00>HFST@4}ZUjhft6C9~S@&oqHyU)6&5MDZq;=_5;eAus@p}?7PCVi2z&hx7k z{$I;Y#{?rd%9BT!DuVQ8Wo0R^4z#6PUlK5CeW6W<%CMOdZ}2w#ry)&7gY;}lGl z-+ZA{(Fh3gEL-sWB3Z*a1x@epCeT?+ON3wIPPr#IxWdPzD2^0$d&)&V8j79nhF?>d zU-SqE0NPgcYm|V?x zAN-~JB|UE<;J<~*YZv#M`yegmXfN6Hnch^N?@(|a_bT;Xp&!SToJZo;D$j7MEiOK! zR#Tt0V=-}~f z;%8Yl99NwN>~(>=FG>aKm}B30pVQ@!;d)7Nn#2VAefmw!Cl7A-P&=2qyj~bV{1k^D zn-Jv28n7fjc3;lUsXC&yrMlj@0#}4CT_vnkY#s5N38pD+QkHIDuF+~c-L_{W2iW~QJ~c( zPV@Ky*4c@^aF1veI_@nxpXhp&=zI`Yi<-`&+JfBl_G)Eiu@9E`GUk@y9}uL>K1eNM zvjm$GY~7HlLLT1(-zvHDk-d6*^c#gp$ofiW1_y-6gsJ1DUkLmDZ8cxCRR{BOO@*W; zy?XWlw1tBE)p6PHXvu~1`H{ebHHxgoTZ1*W*QxRLv&YM|za)#PA#8fTcp-MvKSz~t z$Ob}eo0i*=vF@hYcLF%qo2BkYJ_;Gwn>D<*{MsRr@{5Sx{7W!c4=Bg;zsDT5vA#I- zUI8-Iffu)=zQ-o)R-06oHzK|(cOfU<_pa)jT<#v02y3X9Y&cO+fm5;SIPVEel*n|x5D(Q8RT;{+^%114XFWaybcCt0`fC^ z8WMv0kW!h&4A9mjGGaM&f>os1U7y9JmR*=%dsUt8_B`Z0Lr+%PJD zKI9WDK+%ETU_E-q+lTEQ0+G9|$=pO9!3LcimWyj$F-eZT1iu*^`93m=o}8x&Qk1F3 zE58wnI-3Ekjm|5jR9`Yi2e%iH{d?{HAlkMi_egsj;fMK{*ni&8 zFGV;%Mbz!K-{`dske1!mbG$!8`4LdqNw9zn!na-|ElH9+PJK@&M3eq2Pi<}fU&OrV z-$aewY(INyVqlxv`L+IB6rr9V0NVt6xD|qNw5#Ik^bx(;QG;P-?53hrG~5rTpNnE8 zb!%rce(O6RB81=^)%Zy(TZEXMC|4NHDcDf)+ZMFw;!+}G6j0zGV=pU4gixS*bkk66GCRMd+Qx`9EXTSVa zD>_Ag=0tD!HwA^RCGP3X=NO>Rm&6Jrb+Rx1v~w&e^`GZ)>=^#T`ETC1iffcA-M)QR zzx<`hE-`7d!DW9s?+_h?DXaXts z192{@r_T4U4?z_RE$S;8X%VQ`!+Vcj`|9e|=x)QQNq{jMtVV!L!7Nyi* z3!{U4rA2 zFZFv$uPOS|V|6En3ziYz(7a5Qd?R@yF$^A=lQ<6l5GS)3pU04HBC02?OJ=b`vBlIB zq6m{Il|#Qw_oZ%$Q>esKQj=`b@N%ma;zhYrtZWjp&?dcYezM@OyJ|LIhQcyN__z6!D1Y+g};8Q!TI|CzEnGqmAj3NnU z%oG-x$9-Z1Kj+6+N!n6^A$%!>F=cT=YW@`FzXxFTSdO5&1!EfLeg`~Nru{G4Cg|Jw zEM}4heE5LjJ7K}Bu!r4u#jtxBnS>PZ9iQhfjd-VxBu+jBj4pSnbt`s!HA_uTlS%^pwkPBPre2q471xhB|8u0=?;zy8BTuCoZ8YO_UCP}JZJXer7x6|cQr zgG(oRs4N(o7+rMnbvXg0<jh+Luy-`0hzs}#rqHA+ zZB2;sV>Ddw;i$`Y5`hz3JXXnr)Xa5hd-DbONtilcoALJp(^n8^@}5E8IlNnHlQ^7ApJdYoXb^N?ph7qg_;wqV%!G8e-!a z(aI!y{HT!#P7NnS2<6dE_KN*zpR@ezp|wsfiM`zutJzoNFt7=?x!<=>bGL{{7k4ak zH6Z#|lD%ZQV`}4>ep=BcY|snDeBT;12%DL@G_YtOX5r6mNt}(ZDo7ppR4(RN_Rfi_ z@lB`!A;U>ZG(~L9Bw=XQ%|3c9Aq|5-?woiR(sA`b-q>UefMF+k)Ik3cwaX4WetaQx z>c5v&%~Hqr>%56w-_s#=rnWPG2(>tf;<$*N*FEeiguil-f41wFAGJAkgcaA6D$`+P z;>!OJL1T?j56d$h9@9 z--S(KV1AG7K@j1TV~w;4OFLj6v{RYj#1`MeHb*KMfH(@UlZrBS6P%Agj<^mP7DtRyH3UE7MD|3*^&9=AQ|i|HHT37bn{i7S>x+N>>b)Kj!I#es zR`()0q(t8uaYRJ!*_Wu91x_Ax`fl2ALZi* zxU2pVjFmfy9S1-$bvpVs#4%_C(Wi4lk>M5IY zZ?zS6N1<>y^tc|P{rf0^$PP@~&ZTno8W zjf`$+tIemMv?yGS3e!!uAlvXaqiavgk-&Up>Hf6u#bv6kiJ7vrGBR5#?r!1QH9=Mm z(cBr2|G9;0CCKIB=(jJ1(9Mc@1+E`#?fjT>$MCCf-lM;*7FRl| zhwTk2vr2%PVC$1}%wJx<%~hwkpAZhiY;OrpX#VPX!OmH`M$%G-l`QM*{xx!sd}?3T z!Yh)Y%djp0i7J8Pnp(b2=8EFAwfqmuG+KdII)%?2uCS0BlA^JpPi_%!r8R^tuDCi< zFg1|oPq0G0@Rv;?k4m5+J5n#w^m$RYn)1u~+kKr46=P$o>Rwv$<4#R3wlZlwvr^e( zvd}|5oFObi3UMjz{8=*LxRslL!n0y&Hp*n3OjT@2COg$=FrWH_s(D6GZ;#?&p3D0w zyRPRxB1CdNPotI6(T$j)i*j5hzD+ts&SXRxh8(LY+g zh1yYl>2mNU|F zhvz)O^K00^TIAYSfe(TEUie+Md^VZW#mg!L<9i6{ZW)^3AlP1M%2npK$tX9m8c4Z0 z3t7fON#}G#PeUL>S1CRk{2NLFlEObphgdE*s-I&v-1w2b18G%x3)*Bp5_HiA&mkd0 zR;3sM3E!~Z!I<2h$!yFav2SsIBTA+AgBi`98n)KKUtwBS56!@kF#p%Lr8m=JmKIhh zgm2X|H5Im2dIccUt+BYg2NJYj%r`#H{}F_(65c+{Sfc+^*yp=~MeiSJZcCUmQ#N4C zu;aX44!-lVcA7`G-aJE9>vD!6vH!kUF+z~;`LZTS<2=PR4DR^pS z7kY{p{zOLYev-?=w;aAYQr)W#xya8_v|Rc?N;F8u`s(0vrs>|P@tY(Q9#(J5;sslD ze!^VK&q}jNDVPnkIJX4Rk##v{l9y6>AC@jZLwMp0%Uin7s-|dD^ptHy5*I6kU{m=q z=(B6A<+xNmuUloDgXDYUN)~zlDlVb`A^gUP_PJKG{7yZcZfjfg+C%Dk<@#FW&tTP3 zwaK(u;>y0CT9V6AkF-@#7T9d1AIBM7G1jl3SbDzcT-UyZ8l0P3HaI4*U1d0O>*y)) zc&dsjG+-H$X1}Nn59(Ta6Fwew0|hHw@?Tln^uKOjV$pE&94XpAVpF)Z7u!*HY8{)$ z=e{dh4gM$FLAB7jSYrOxkv^p&Tj^Q8f&bApff_MK|3@}x?<8L)mf|V$uU-NNHE=(m zjTDhiy^wA!`mjfQ_eB!{?f9&^B2B{ky|>1(#wB)f?z2f%NTi$dv$DJ6&cykPTS{}f zT+(+!Zt84`P6+$#B!1;Gi7WUXm`|P=Oz>#r&HB5y8}cxkD(*dduta2`VRa2_93_}-beYbgnQ5(}JrESctSEIw?v{!nK7sBwmjn}FJ1}77u zmUj?XhWA+xGu?eG>5Y9y8JzADy7fXT(mXr?Sn(&ZbEIPA`X_LjP0eNL`U5^|H|qLa z(K_9Pl)Jumqi|X!Mz@D6)qD64^g&BJ+}(eg_nS8ABSK1$5O~Ppy~r^Z*I%Zz&hTO# zWwnv({!G&w0Dj1I=#9-bypMI}<6T`fzglm?3{6kJzux}_AS{3nTcYzV0=3%z^{pw1 z(DOIU@?v=YBhQ|f)97zx_NA-A1Aahn!BmjH{{igNtQ2A&T9!3@yb<^1?)Zo7Th0U~ zx93|9377_2UUY*r!XLTM|2frsykTHYfWqM)A|;zxYKwew!OVmERB0adf3yh747p=I zpsizIN0jMM<;k$PIrof+|6D&F;@4ujZd=}eNqr(-w>>8qRh`z|;NKS9!Xg_-hny@`0$Y43j`0Zo4rn9&P!Lj!V^4_eQizZ{}Q zk(buS_1h$8^w{04ZN1A~d*~jfA<1Vg0K#IvJ-KEa2G~lV%*F$bbQc|{qN3?kbzSPh z)dKsn_BIQBNfyUWEQFy#$LmD_vhjcP8P#6*EUv1K)hF4$9{1g zxwVxNwMt@NT9&c}&`Q1sT>JynsBwPm_L{!t70QbV1o5d!>L>6WT+H&(-`BT36KYH4 zzWUoTH@Hi&qqKTrWYkMpypj4U+P_W-lAUZXHjI5^o)7jL-}H8($uI_dj(rzV9mN}7 zo5+fd{Ht|piV9Zy!{6k1&W%1@Uof!kE+p!u9=62*)Jwp85yy0XA>n> z3oeI>6wljy)Fc=APZ7U5!g_qIM@;}3FKp^^m2L6gq%P8I2R5mbd%LsavfxNLc3`xc zM)E7<+wkdSFSydFH@x5R(0E#RrK6w;5~@hO(Q#JF z)ng=^^5|hd=tc@WbvHdUbw~*D)A(&l!QuD9og^3`Cw`c`ZlfAgqxISB|57} z6kZ95?Z)+YNT!%n%~Az+t^&}P2j#xFSs!iTuRn41wO z_8H$*AKg`|-^3=_mZyG}MyWg_ofM#e5LhX}?yBbd8u5eiyo) zxtS@QT)d$4U{wa6Q8XYdj``# za6hnhVPBEgwoVax>!IlQJeAg56qT&VN_6puubwZtLJS`F0f#SI zR4oZUM1EyjJL8n4N4b38D9eO|EKl2eb0(AQQ)PJt|M;Eq+^-AY|D8$POBo~cnR2R;h(Vbr%t*y#zP~bmGLcx^)^XEpnwBkqVl6)B{y~v zAJI>UfVeJ&w(J#jKZf&25#wt5o6C*bP_2LA*u|e4SViQVVYNIr)?!1>_#Yz!C$-`8 z?{t&l@;y}0r?gbj2U{0A(V>J*SEOc28DeP4sCpK9z6%MRzWo4pxx%p~Ou{oxMXR)n zB((}!b(mFCY7450+qbxhQ)(ke-(7=@zK9mQ6UTON9(2C8RbUZkvV$~`mq)D5FuZ3H zr+a)zxk;X(;Er}D#jnjkeT4}8NzPipe66Rh40p4%eDRhduhG{z8=H9bPjd0ZPSE$Z zdBFU}x*R7gY<}c?|6YYKl>ILfyxgcZ#ZDx`K&twC672YdeKO}u8)PWLrdQsn?nXv> zLA$j+njmL(!dmzN1Jzv4GWp1mtc_2kdHN}HRXCad(e|Xd(oYa00F&i)UeOx( z2B0JXIk5rFSG+k4Em;eiMZEvg#zC2`GfEI&Z=KocsxaMogqW9lYYw4`e`{mR{rdGc zCem*=&3&<9oyADJ9|DNk+-^(DkrV2r#v2t~qKk1;z0ASBMEO5{wyg)2 z#cn0o=LzjB7oU%09AXB33n!Z$stl5E03s#ZwjVETp-;IF**l`&do#C;V83LezSq3A zwsB;tor``7ue@;FppnG{K8SvSyJ|l&JV=X&V0Xi_zT`H}L;6Rg`boNJ1Reu! zSNe!8S6WV=IDF$9Fd5OGK9$JO0M=ptFT~weZGI6#W-0=HLgpW>QL_4fZ&2#07ksAy zIzh_q6kk1Dh4ehY7>U?Tz>q z(h`0!_@+NZWQJb>-^XAG2Dni(jZaj{3XSoz~GgQ;g@ec0C3P73;w$E;p< zOHQyvTjO1?UT$5MQm2+9gZ}Ty&HP+)$3`Vti3A&=X+rIkC6i<{l{S(U>Z!LTCLD5L z_H=CcsqiK6nx_u-MynId?%Jl3Ys7exsEjhmB1)ICx`WhBeEh3Fo4e68oi)%iB4oql zoi{l<&xG@BF=r!)QPB;3vduPJiMmI41MW1O>FdP5Y}1qPCwDy6kJ!|jcX@VDCXE`& z5ySLnr5X4~O0tzF*l&;jH1(MCYkoAzS>E0iN2o)#XK*@(UXuY^e}@!WOw>IZMtNMszp^-R$e&JDV-D;9Q{W z@CX>w#kU$>cx78Sr2N&6Qt~E;8G*5rIL1#X5mjEXTbz!*$zSEiXmgSx*3YyhkZf$8 zz!*qVW@<&!rCvwj_7WpzmI5{^-sG|)!*TioX)x!~*7 z-+I{u>er2vmWiQXU0HSjqln{Bv?g}DTFhC5%s$IC7y zJfvj+=2;;olKbIa4ivI-4WsHs#x5Tc_Rk^<=;!gpW$lNI=9{{9*Ftb~-}RliZZh`! z1@;~6hAp(b2%>rO2ItmQiWr(01|h#K@BuGR9*veBRj1FYrR?XT z=q|KYWbBRSyF$fb>Dj$$V-7W^k~8ndq@WwtcblVipJQ?jOiM-ivnbiyctuQFgGAdxvHrpNt_P`6_WT(zaW!ZECke^S25*VW!z`CGNSK z^%qBz(QB-)GR34iSg5ol^K`|Y?H8Wq_Yc2o@iI&^^c?n_#;GF0YumUWo$rs>j)HVA zmCYTKS8cfrCO@x5D^Ij$ecp>QG)ZaJDIRsjUA=Sx`q7ETW9ZbdY3-N71rA--mequ0 zIhMt$xR_9~bow`a4rp$Y-}LM&s+g_mnns-*7SA%=4^(hN;wnqYACTN+0<=0^Ta?#CJ~)WZ|0WG@~S;$%V1JAJ?dJJOow5vfa7P>Uw4rprPO`kq z-$~Awh1_vHgw(i7Ka)Kq(eYJu)xjFWzu{ld578O_UuHjQ1i(NTzWZi>H!DG)&z7L`9xqOB8qJa*ji zAB`o=IWqQ3f_#1#xYjBHt#TAAp2BKjO5hGkfN!x|D!2>S>I~X}azC_>6qTkW5Y%P7 z3k^+SD*R`xBfznRk0LbBPVq>&`GCs))ePcKGZv%V;x$H&F1kL{J3|P0CjG~jgz2vg zq(xpEg*~chzie0zwdizdRm}tAgmNj)BnRy@kDuyK`7j)Y|tXp*Tx;sZpgKfjPS`7sOA52!_V~f55 zL692TDGxqV?;$+Ly5CF?j~IV^>0?P9Y|w6%72|-{c$EML;{3^1=4>`Pk_3jyGO#Gg z0Z$(6`oJ}yzx<&rPho!kA}Ka>U1T#-WKdwbkX>X7dJTg_<_9Vg8Mu=7dla^td0Qnn zg(QxtwEqD&EM#J`ARfMj`h@4NDLqFJ`y#-DnwNq$LdPQLfom4gt_s{H)|rA~qh66t zWGs}Hjpr||#hAzt_B~JZ$dF0Ud9G5{Q|Q?n)Z&B%e`xW-a;fhwz{L1#(Vvzi6?xRe zLHUz)D@D*MfH-2#)B>5?J0;pX@)GTu-8XK| zRc-XaP)OoImW3=!Z$d|(kmI`(J0g#KyQLb~@6<80-Zc25YJ z?!(h{!S_POy>spg)%j>clmfo3vlm+W>;;<;{BQYuJbC(Wp@=7^qONT+$J^G{ z$D-J_<956(4j1wY*rU;&itAJ5cv^AC2xad($4%rLMKMb*lQ-9Zm-;*7;1REjZG8k- zXPtl^ldkWs-BT)tq1M0vrpY2#S!~Haa>^250%B6(maZG8m$T>@94RQwty0#eG@v05 zI5|(w#~N)t^=oZyv?yAOa&i$AH*qYE)!_XhM$+-W`wqdU_nc8{95_}u&m-S(NQ*HS zmG2Pf#PM7OCrmSyeVJ5h3l+Hb?pZL>Vn&cQ>ZKHjiyxbrMc`#gT;21Ub-xSM!P90@ zi7r}?JR?UXr_H0274&GbNrY>ka9ey)MbqWh$4;6hKhjtsRHh2pKrHh)oxm*y2Aj%0 zzYOYAyT(Mf5%XGTt~xhm-fSjt2-n1;sfH^jp}mFls;D4^^8w~UXy>k54m zE`F7LY7+$LxaVYdVhSw61pHNL!ee5e|`FMh{nRUOlK&x*7dtv*KhV@Qp} z;OX{hO=X~*ypN~@I%L#tJ37+1Fs)lMLUSZrtkWEkim?-m-Geq;~_*kk=0(x z-Oev4>e+0zn*XvwCh?c*KZTz4gP47)Fi6^jv=Mw{BlRKO@32_ozX{!UDIN4&*M$;P z$>*Z8+=uKPAE(qyLeG6=VaLRwBsNxhjqp6sF2&IKT_mt!@~71nKgNrrTSBmG;((F) zk~>8r)2lYG86+clz{~T~rO44L0aO!yZb23$AwPtnH`2%02gvTkS8=_U(Pu3o&QB!&F}KqOZFWL5|vG z1>R+C{C`}o%HhM=hwP_y;HPRa_H8nCEQC2)m5@(Wba2H2fkWmThR$4b(m&}K-)Ca_=X$o4z*GD^?^NNW4#Li1(NFEKF zSJM8E4l9?jiA>sx0cMVI{DBvin`kfJtYNXGr)b3Labt>I9*{!5+v9mPqT&?e8yeJ) z!s|(`mkDCN;z6nXb@py*l$6`jd~7tU8Fg&{cTuW7%cGQys^z8GQTOuNwH$Ve+wR~3 zrm`J2)n2d2X_ohq7av2astZ$is|sItyYpZ~a$kQ0l#m8YPZ8s1$9#HR*kk>KBe+qy zYy0+EuxBQA_$9eT5qt8KlQNffB7XW_T4?aZlrU?NwtP(j#$VZ)}XBR)s!!A1SF@I||xbaV*_?Dg`NuQx+@%2yhGlMxU zl>qN}0SfKATG+nrR@5L?303${f0+hyj)47c8L7yLJC!MpP1!Tc07PMb(W$`ZWsvf1 zg)G7UA-d|zhwWBrnJNq=llLQ}1@KrwNV6FzVKV+bfo z8vTRJMrdtvQsf$Ih}}A>s16x1F3X_i9;DL z?$=$e*2!?BY`sF4Z|rO=1Jg)%s4A(77G2dr&!TQ$hry`^!{43-d=CZXq+~*H!uA+E zrt}lVt=Yfq_?TnMK5A_M81r&mDCinw1}pSN{TGoTD{K6%&2B56$d79udNsqUG6nA> zWj+Pp1P2L{zV(p|CqY+pZ=QG$?t#W zoSB zBUW2KKT6#5j^${kHg?}f^W6vWX#u&74mQG~RP=*~if;Zp;c+;yTr(r(+bD6-%M?-T zApb*P$dR>)J5OF>7(|q>c3w;I?St)}eU(eLO2{Ioa#T~bP1iU7^~A*4l`b2jxc%$Y zMC$qcZr=X65CmmAj!0uE@q^UL!*P6Q${ovEn-!i5ac~D4M~fY!koDf5^xFyWzuU~D zpP;FFzh98;k)A69R8PS_9@|)lF*wSQNAhKgbqT9OkzXi8j>eX!hgzj!nswL(AQ04u zwYO1Y_z#xq>-n~QoQskGwqyyfXMeQZ%hXWx;&(K=H>i8XycdgX<7}FezP0&+^UUiK zbn6*p;4yZh`Nei$jmCh@Odpqx;S|N-WWvsJkKffZ$FZY&#nyy#p$czG?}d_w(JOwh z<@A19o=8C3Q3GH z37KuuglOi`5owg*_o^eBaOpz14Rfv#jGx)1E46?oFHNsiVnx2RPJlR<%+2j0I|O=* zX)?`;zqF<)1dwg-nn{c=-dGmy>YA>ZSE}~l>%rC9@Qg~$a^vxs-OhL1)Bi)2hL8#@ zev8Rc;--d4yfyHVeHzZ&>H2Am&T29rZr3_f2;4s-;9Hq`It-=Gk@~~ojwuxN_?C`G zlg=uWL;4d6T7F9VTBVmkD>xI?1QrkDD5#NyJM;C;6c32$6y~-HSn`mFhm7d#sc(H= z_&3~r{gLU?QloblBocmW@Avb%Wqw}x<)1)nS!iPULlOpU0@>W1D?>AgmJPHR=+ zYhSi{d5X(Tz;g#hwS-EW&89pNpk>W+IZLPpK~1+ep~*u&eE;{HFz!>`q~8KExvqpa z&G2hQ0jZ?HW{w|T&rMUNkVS{_@cqi~jPLKndU(ti8(qT!G?DDx!$&Q4VKEV-L)RVS z$7COt=>pDN*YA=Wbp-ykcAS$|D0~355Ri0bJ zx#@+gV|ETlJxyYR^|fN#&SCxt9*zFu7pF&VMdH)dNiEF~PNV+B3ZM`!2IC2(w9q5O z-(l2{jzFQ@`vuORv+HPIYUCd<-Mj8ElDb8_3`dI_yhbae@mqYlZVhbwx}A3pYK!hZ zqV^-djXx(o5XIJ6u6q3GMv;Ry@r)^WHyV>nKSuoto&x$`W22ZzC*=*6svUNYaStCz z2Rl3^rUc^@YUxbZ#U~ zk@^@?fEEokRmPE{EmZmT;OJ7S4*KTJCl@)X?^^si6EgniA=7gTDIsFki}F2KERb(%hWxkh2Ko6d~#6St+xmr`Tw| z-WzygNDn0Gt*_DMp76-_RCk2K#-W{kqTc2?F7R=bL65TzOGKPasc?-VwWcO}MzdDg z$!Yj#ovjR4^Ro)o&K=-y_74Qh?w6^hY(?ZjGzwpPOwoDIxEprYH;Vg|-p|TPs1Iv1 ziD|A(S;xAtPwcBfzGsbfRhnO}-0o zuc4RzE6pw=&VX2#q#7#ca7BKGnoN_qQ^?12mg`s7N?2CyuN~RIrOq;hcZWcCDgN*cS zYf$%(Sv5Y`9yXdDnIW1VZpQc;&4x$Ml=blfHUk{hK4r9i3u0H8yZg#hEbPv<9-6ok z1B5^EMZ2^~0(n0Y)!P`>@QnrnW&nBITHgb~`$+O!Pgg-QpJlHoR{{C5W!w`C>hp}6 zKJo8Q?s>U>@b(#}^jI}LcBP!+r$kZG$>+*=xNGY+-Hmp_ z8}%4yMJ_6JwBtJs6WO0VczwiF(=`&eJHKOF%RxT*!OR_b_tN$BB?hyl;1y`@|5+B} zB>>~BNhQEGqz*g$I2jWWu*=^fbD!%#*o|-AKY|inZda4W?+9}Ug&JymiShMsl!cl;@|x~Ow)v>X#jqV?qj%I% z)^I+u8FY?OY!IKB9DUd0=5}o<+yXJ`0$3Va_R2j4Kh~RP^#b({E65FO9_zA z<184aH-3_f*ld>ftZc16=RS%?450-z*tEMwB{kkEWKc#jdl%jqd4Rt{0XT;H3cduz zOfX|Y9O^K=$f+6zSN%NcSq}ts=x|bVDr(OUg{5!H9;+FPS0Rgd?4}PN63%fs5+xoU zZ999_mfq$LCPCC<0OZy!c85)FSjSH&aKg5N96aRI7+r1xpAlMx$>NzABQD8eziMfW zj`Y64Hbsf_-f2K5o)?tumOowl6u*DD;8uDhd1-sQJMaH8ufW>AXU$EPse9HPjQ-r; zc~2_jearshmlNZ&L+`VRZF2we5k4lKlEh9Z7U-oD`6^Xt@{61x=SxwRD8KS?h;sGl ztbQ$pCME+RX9OKdVQ`3$5%HCuGRr;#^xs40$>@CFFD>yu=qMYj%x#RQ%^#5Cq@5S< zyx%3XSbQz4+8ZtAysu$f;~I?;u(Wq;jvCi5L^0LC$?dto#ps;cJ5ddAA5#ztf7IXm z%0YMQur8qnUV$5|vkpB}F`J6hs*l7R?OQ#gX8C#W1M~(BT<4sX0x6#g+jhF1Ob=k# z#j50^Hpz|i3uwkg^wQPM&u@;ubpqdvD!D7B;!zPw8aWl{cg`Oi%LFNZ%ft|sLcdcFcJp z*a;R>iaz~B?`P0loXLL9^bdW%9J))d#rs3EBE`TgZ54DnBTT9YqYynWOeLA&u%py+^gHG#_knE7xhO9q9`N*F8^-UH@zjlmhseD$lr5SZyuLQ7UNEv~h6~SP5_9v=MsWp~3D-hMe zE2_wB-SLPBt>gXo?|Hm4C@kcV<$Kf zqp2*9$I`jrgvuL`s-!*6lJB&$?gGs)!HLBHnd*93TW>KP{T**}t3T;$@21*2ES8HD6_VHWFGbRuq~OD z!+@isBOC*#ZlJ5rgW|V5@Nn)O$E#!g)@`cu-XH2078BUx{KIh0v%*BCP;U(EKIS?P z*Ef9qA!~hem^sJCm+h{J1W_JQ#*&}Z5TAt|b0MErVsD4dy&K3%&(G)8rQqD4CEZ*E z0wn5=NFvU0te*wW+eMFyheiq8h0+xR8AT>%^F;jQ@ia6UW zP#u% zGvcpVD~x#IZW?KhSV+n4h#*Grm+MWm0%cKIowR_bUQM!Q$&GGl{ z!1Oabzc%lVv6lH=1?i+GgoK?j9$@uPNH%TaJfXdzyi;pL)G~Qr8Tr=+@8DQzh#wyJ z;}@27tSV0|RkhJ`jTWO>UqPGR1c8zEAb@8p};V zl#NE~6a26j&mOC1G_#L9Jwz2^C)zi18^iwJmVNf-?HApJ|M_iWwH^N*=wlN#F7Q0{ z5c}V47v|bPUM&lK+jn(>4a>p+2nSMlor=~sg?t~8 ztRA9lg~%}!OYuA+!>%6L%+qpNTjJ#BqT|=!Kr<`lVJz&wiOE=3X#ywXE6Y4wl8XAa zad$DRz4f}fSoy~IiaMSaSXiwR03n&ufX%V^`#P1l<_k3=&fd=&vBWq_u2@sed^=(( zSBa=~yl}(z(n;)uTk*LvPW}W%>TbGd32E1d7yz>MsfA(>U7QGWPMxz`NFIUhFmK-N z1aLiiaAy_$`yLL2MII915N6mYA1uC0{Z8HY7V+@cEJv%q)#VKqQN)!G`bgh19MXKy zDtQN#0$}|}DIUycIv*cGC*Fk<75cLuT1J8!dIqFwS?gm8A_Fc}s!E2L$Yk3-^3N8> zvmvsl?0q>R+&8p5ZgkVP$TVT$#irINx439O9dwGP$DtxY_`pHBV-re}Z#>$NRlU8U zx>I90c=Fw0*@2Y1oJ66#xCVLr2YzHuB#NDqI>}DT?GSEZK6A?0Ro9CK>1&TtLEs{9 zTGf5f!*(HEoQ_h{HrA%!sOJ2i&kSpqJQ$Py%gbv6?tc63uN~{Y&)d}d2|3RUosXrR zBVpnrjIku<@&=ag=EeSn14S zX_9^9pcZ`7c|cduKolb3F)q~l01lY^wO8QW_(~wT8-hpG8LH8a2n?9 z@2&AY<8{XM98sDAro=5ZK52-V5}mli>Tr?w@KlmuH+sdgVjMQM|QlhJ#1LWN(uMISs)p9`3^X{hq!X&o+M_p9-j){#+A1OY* zrT}yXJ(9SuT7$cLwALLvoigjh!8Lk(Cwy!E=pE1ah|2RACNs-@)sMVrwDXvZN2vjE zl=cIxmL-plDe9SCp&KEcm6A0K8g@|)=a0NdmnysE11E9wuGAtGNbBkSxI8&ir5&#w z^K!R%KsNYk#t;JTJa84gag$g)@Mq1S{@?gWa@mHP1{haJPGZ1QpU5vn{HyX&EZM1i zCXZ=Lbwy2~;4uu#0)$fm{H4mOTY9=3eHyigQwBd$7tJo|$z%RLO~2NTvA^?hPRXXi zSo?N(6Op6WlZ2#4>5+DR3r_Xu@SS-{Ki0LQR{O5%m7a87YrleBP$0~AV_kvzUvKU~ zMWa@vF?2g{UQM!fd(=0+3;+tNRxaoBSbq@)+wGpSAd`-r*qpnt5f8;-(+|PaHSPr#E*KEwI^v3sC zm%AT1MQGP)cX&T-&{1j7_h)QWwx*~w>Q+1^aGJ+#yz0z1lV4pv0U{~Jr=IBY5o1Bvlh7v>1svN=)KDjI-iDe z1A%5g9m6^iKP$nc@)ey>JX4C$zML)(Yj>M~;I4S=PYV^SZ5=U9J#>#T+fsv~fZh?w zgNJCTa!;n|x47E&A`joJhF#(tosw1RbuEK6fQpKgy3Jvhydl=v);do29j^VUn#mk+ zJ%WmPbZw1|?ibAT?RM6;lt4R^ZTPPMNYLqgnen+Ca@F*%{c{CNWe+)GH{v9a0 zF3h09CSd#{>M2n1#a{Xa=byNFDEeY2?V1F1Lm{m%B`Dmiss z*$)CNlFYFn&VmBzHAcHwTOL9l(8yT%JFJd1am0jlOQ%XYQEq6bX{6?Fl@R)lu|)NL zEdAMqll&+MvyR}Q0stc&L)~4Hh4Qk&hME|y>;tyX-vjKB8|=4iR_d;aiSifUcR-7M zRw6(Htb4_GtWc|Ue-xuh0vb)z(=D+|JLfqQg1@fv#klpSVmNE78y4a1lDkxh zCvV$uQRdjT)`0i`WkgLVB-c9wp~>;~<-`MK?_u&2>zkee_%{3(EBeAOhmi2&whibK zQ_WAGDEaqL9NOzc!s@(6OzA4Q1)*X}J1~dLt=|NS>%z4gPSsz}?lGQCJ+|2Y46wcu zYzy|a*;63C8?^4*A^uq>pULgcZaaB|ZB)aEqH-wPdS z`u+50uFqHEAxX&-KpaRW@BBINL*G9s;Wb|0D%{A*rL=7;N8+aul0-z-Q7f2Eiw65d z;K~7MZ?2>Bm<%C7*k$ziJGw@}(W+V4#VrLvM`2^tau=FedHdSiS0jTgu}r{f^Um-^xi>D310Uj$2X zJkjV9*_*W_4BLp*c?P)QE+hE8@!P+4_~|F&K-t2f4UTkKhxwz4+?rh9 zV*E0(p8>riM<;}J#;{uC+;!$$uT~OtOPEW%MSp#9^j!Cy>hwnQppVh{w>|#<7{H3A z6vY*W-rVcR4vF=FzaIr?9F4lw^hvR$t&}Q&aM97PMA0i_<27?tbCN1PB)Qu-h_YI# z1~v1h**XE^GCC|uwt%BEMT<*`Xi>3`J+olNBZhAnXhU7%YPvs)9L&1v4hxpplo16- ztJZi;g+{9k$t1;66Fxfwix^_|cCs*S+L8YV9gajIu4vnALbJbx7fks8a4Gv7>c%w) z+1o_S@*cB#0vsE;$=biJ)lg_@J5I)D!=o|fpw0O=RheOY*m@F~2@`I)^K|vgI}e#N zwo*pRmuVBG!w3cyfUEKpGhu$HQzs5W0S|(>Qv+o|=_t|553@h9NwJDFb7Ha@B}l?` zgfpy&l)t-N3YFMWe1U$*XCP|28fBoC9I zk>I`RVu1bT`o4X{Ka>MsQO-F~QOLagTADsxv4f56WDP@+urbX{-%k`BnxftK8IEE2 zjwEq($G8{K;V>otSNF;eUh_pu6vsckBln@};T~&#@0yAkj$D%kAzlb;_T1BIm|;i% zUl&1&S2j{H=e@Cy?GMz?-PAj;FK_|?a>w~oM@;9#M;Mcu7?cRXfK?_(7b?oL54g+0u|M79GrcSQrg zR1k>&@dn3N3)vBuwWy3`qkdpsP-Z1m)MwQ#*jT-zW+f@8Df1Qcw9BS%6J>l8C~sfj zeV1GPGIHlFPgYoup;ho~=2|xRTKj1XtW$MD0~Bw-q#hTd1tbEk)TV>yqWFyfRI3Qe+M>3cIgE@j-yk=6-_mza1OlO< zQRej6n4ZJZLzN7yOBa*#)zvOJ>ODOQ*vL`KwX({EG)-0=K~OfZLQdj1UIWqaan1hd z+xMV#x-lecvaWHmFaIZbcQ93<0YfSrurE1@4j=VI< z5If>`lZfFcgYX{CmdNbAnyV-2d!BCKy`P&lTT|B`@E>3Ga1tHxQqC!RjGr_XcFjI9 zNVQ0T-AouZsyMgt6b+?j5z)p_l2Fyx5B)pCFC|yucB{VSSBkh0<3UNfC#{nofXmJ` z#3LTF$>Ul%LDX_27$<&Wo_izk!Pw!%BvP}=93#(u_Rpu*%Rk(=u3Nmm8!tYRl9muv z_jWj-;QmQ!10o=r+MTn~CI7%&1~h5KoM+Y;L= zY&<0dZ;!h=!h}hDxVxe+Rp@YFlpW6qt-Hp|1BH*L;TZOd(3fwmUU5~2%jLeyIzEg0 z5uYmtA#fKFwef%aHH~)$L6jOD4>&bxzgY4Aj!LN!lpTl-8$(Z;dI`M2{BzXeE)6#M+D|}VL&aDWHIwduTPK_UQDH`n+ z6$jkdH54mK7}zQEI}%|w(|eL7yT%H?vHU08%pYthW7m$;l5*|#Og)VgS}1G9QXk74 zemmjb_((X=BS!H|Upe_0F1jZyNuM&ib}cxezP$DHZ>hr9y;>|FhZs(hOz}(r?dxs`_!d zRPVnV-~2GOXQDATKmQO%{eUli-;G<-&@iwsekb%guzpW2dbi^2bLO10{rqr!a(4Cu zdNey<)>>_*5sHpW1=rvuzTtncWx_ZjP*?4`!AM|s!K4vp%8g<8$hV<|qv^^cn7=q= zWxm+|5{3}&i&P>Yldfc9%=eCQ^3Zg?DjdM`&5i3z;rkXrH1;$96njnWQhbidvr=?uOW-S9g=*7 zmk56XCBYmj04b&vtl!WR4LPBifcry?>;*jLV+Kp^rj5&l0;55HdjkAaKVvMjd-;djA07zaWZyMqfNwe%-MB(lJbkgkjk?cw2E zObA_pe7mZL`P(+*(pTqTyvr1_)RMM}4DjU9Pn3J`_ldZ8H~C^!Y-!3C8So-D!5Z|| zk)ZLs$Ttl{NB$f)@BYgu`H`$HNnhuM7NJaOf!vo`24)OhqU*X5VAg8qzZ{~qPX35r zA$5NFxJLJ59TNRW-Q%p4qKz6N8L;KIEdtf4rSg@|@(R27>YL*D86;*J$2@FkX>~^5 zitYG9Y_J#Q81T`r@qEK(Lk&?PnDU@;A+$ll8u~y=PtKCIN_Ie z6{R1jd6YUwaJ+|knIYr}bR0ziMJ<^&NCRMn1y`8;;9gs^JLB;*U$Uu9sUnh{I)`^F#NuX_q@n*)dl; zqW`wgv*c;W^;&UGL4GH?jH%utQolX#423*a_9cdrwzw(JSP#}isL3Oj4OM8zH~t1G z153kSZR!=qaO@}Bb0|2AN`h+SZ0m>n`?{`205inOOlWe<(+HE6LA@gn6IjBgo}1y2#ykTY^m~O7KX^E-x2k~%+Boeq_g|V3 zXMTASNnq_R3yQ+T&OLF@Jtw_MVEz}u)H~jtcix_`r}fGI*0O#lgMPmo)M)1`@oKH4mQ??k@b_u~8K4OW`AcmIV>@1Jopv1{DRZegDzkE$3yxUU zF3<60&XC=JR35BwtU_!uMOFZDc~@O@(oqqLdeXVfhS7_wvPC1cGl84U2{Fp|aj<^# zHpqM6NgK1JWACNuOyUkBD7WR*i`=bhvB7FPp6d`b$7&9EeniIl?01vjh{H1Kt^2Gv4)bt`GdZ z`A-s4Tj(z?tE|ik@AJ6WK=ePYeBt-Iwf0Zm-ZuYl6ZLw#{<_?DoptWx3vkna^-eO9 zu4no31UeyVQ7jfP=~FF&*XnI?Iz6LlpqZlN|V117Ka`N+CP%+oIjT$0ggmE}HXJTI(t4S2-Bn~o#Q zOWjV*#b4@QtKFh>wWOwBy~=931TUOK~kjYO?*E zhS~SRhFB9O;xae;txE0-;a*!a#qQ|RCjg0G7E+?8z(@7Q!((iso97?wsj+;`CG3b_ zzDSmEP_#9ivly)kLbfN2nSh6BbF=}F8nDirs=}SmA-$1lo{^l-ieh8JlQs2Dh6etE zGh+}s4u#)AzFhp9V@nwmuB4}M%5;O(xNYR9FR=0hbR%D2Xfa2Rl1TMTUCC_CrummZ zy-^@U{leI$WNI7Bt*By5WiPE|t_DSk5cmA{ROhu9cre<;hFyx)h70 zYb?-zYLCW;4tbldfml{g;)Z?L6jVT0#ss7*PyXvb&LVcRy}^aeLOAQV7N)0iJZW4r z`RViD`t2O7^L>EEi@QkOD>`Y}W(d@KE$96&wb+R|9PnhDgnq-z4q(x6cHj^0YKE2o zGH$ES&%8tE@%%d+w94g*Y~NeGwdcK$*N1BU@44j;&(6;5lD*+Sk_+@&WI>KT!n*)< z5=9|*Nw9~^kRekayN2A66i2Nriz+h;nOK)8Ueqpsnc`O~#?HU20?2swC-(w%Vi>Uv z3g9ekQ!20J=hCsw^VoB0GgAE5OsXXmp9 z5=M$_d^VzhNW!D`-x@j#k%WQUC$P;j4syiNouz#PAB_c5Bz0nB_3mgU?eizxw)Uf# z-T|k)e|PDZ=Y#;A@hVx=r9K>Zj8q1$$F>Hu=3!BJ7^S>_F(w#cLN3V_B@^WWI2Dv-ZY~`GkYv}o`~&QW%7cvjzcsb5`YHcE zH8pqrSAP=3aaQKp5THH02B^mk6JgG-j4kj5k(qWDLnNwG8AWYnlR-4G>lJ`cAkHW% zhbs3GLzj7@$lX|Dor{c}98dasx$lXcRS;E}7{e(9osZ*Qyv3n5qfHg24Djj&I3lw zBS_ZQwAI5H1%uYl-c(K-V0g5v7KhOGy_$bj#*i<`$-e10E9<)9CUAwe=bRy!h=Y|n ztzFNbC)++RAN`{?1zqu5|`wZ_W_f$BGio31!VCB+lMZ;1sQ zP%4-G3=3Z$I5(4ok+QuKPEYJ|aQht}F)pZ@t`%zin)U|wbgH&ro7$;H+Fm!WEAK#; z%g_#2cp&dj{A2d1_tD=1qVEb8iW)*#p)Ek3Npm5qMP`o0++Cneml91qi*lA;GXXK3 z{Zdj0L<@XpSt7@Yzk>t!uW-T=ql++i&awa@S~QBbQFn?@ zmZ3HxacdsQxR$`A62_#8PEMiUXuw`RU3tTpjLS~0JLE$#GmV#F+__4z38h9`p5y4K z{zftH!lC+jK*=4nIH*_XFoN-Et#*9BcO)6YvkXom!JhnQ1Jc_lRpw0So_T&_yJfz9 zC;FMiJ?pf|n|fzal*TGVkHQ68BTk!NlOK}wCVme`L(NqrgU)eQvrv7Zyg|M+QyrUG zVh&rb^2t|#xEY%fUb6be(_OhkqF((aJ6Z_4;G1GWRD`EMmqezXzw6HsBbjVXZffsh zKLL4>jQEMHz=q*sVCCm*%7nz&5*OW7&LQ_`h1G05#$R^8$|{^&B{_z|5E4^0&l*nV)zO=qHe7Q ztX4y(YZq5oXlqm)IJl!WI2LO+pJ!Ot;wq5kWPR>ncm<~XuYOp^(C5>8R8l&%;f?#s3o z%s!zC7w^Qd--`ZYRhrqZYb=iC&eK%cXA(@L=-`3%bl*lFqwYZwFtq!vSxw<7rjK2+ ze_*&X1;JpojHEK;W5yGS1t{nYQb}Km$eJi(JpW(sVf6}gVwdm$R*Ykb0)OqXGr`Q6 zS#9?nVyB9H{B8KVYeYo5L9kqKbZ^PLQa~r><~bpP)`i|x{GRteIAVIJvC=v3rsaSl zo-x?!0?w3tLd*Nj5y*vTg6M~P4QfAiWv!~Nk}hsC>9;CEw%2BdEFdBld-v&Pz5*av!kJgx;x6`^{xvRIaU%fmG4oJ;mEbBvG09gkooQraK8d-yp>bv5RK@Yr3 zFp>70j*U*#teEh@km&i(kt-q#miECI0&q#Y9B7dL40>{dlKtLhUTE2a&Tu3Tz>JW{ zj>(R+^G**^A-E2d1FZ*zzoCWm5543UrL7m6lMCn{{WzXwCH9|I=o9-%BYXnRZR(Ur zj_&pc;TnaVB-Gb38sgmTA3qUhZ~mP(yuI z>8UEOPRl-MJ-D?yiUBmvrmw=(eLcO8wK=FOzvYpMt%Pi1MMyAd}(9k~WNH)t4!DR84(9Wg5w{x1gx*1t;RXbIhL6 z7ZsI^FYbnAMfHq zH!1Pd<;SyvjHR_n4Gn%Sd$uEcbx<={Po;Sg-a7W4h%r_nD_Tz;$9iW|Fnaih4GFSk z&`VlW&QxNV&FWVz(vd^+u-EO80kzZ946E9(Sc$Vg>L@BE=Q)mF9>%Q2dv!Xlh{Z1g zaS<;5#rP!}G&)>HsQG-Y9(#Qihuu@d%*7w!ua6!<7m|YH!~fKL?o#fi>n0gj@5-J- z-9k~u?y=V7MUm>3m8`G1Y`5agf_J22R%x5pcE3R?VTAci3=0lN2IQe4PUb&rWbrX; z>|haK-(nI_-QS|#0FaJc+e~hKL>4=BR+nUp+oelTljhsFJ}e9WHcOKM?@eNcfUaQh zEwknzWM1!-ihyAwH9_x;xTjovdaPJwWiovbgsS13ZR4{h>Q;jt3+KwH4odm1)VX&Z z|2B^kWJLywp|Z@Pw-3Pf0~+xQ1Gv8ObARjY%6{3u%>Qa*IGF<+q9^q!IfO(C9F?G=DjN= z{}C;MTgC;$tfltGcS!^zjNN>c3)|%Y^+3gUfGT#>Quf9tW7shmHNe3&WF97*CrtTq zsdG{RHZ5SrN;3*)SR0$_Z$gpj4hpvY;YFsW8QdN74)!`RB1dfHt&woE3OSW0{LP*O zS0ADB2u`IHm<2UGcY{%nHW`kHub=?e<4F@(8{#yV>G`C?(|IMqUr%I>i{y?NG1X`Z z3?;O{7YNrK@1}+@Q>HUYGrH{BNY+3@&gFVgC27QGZmX_qW+|67)QV7*et2&B#bo~y zFxz;rZ9W49f7%I8{dBEy*FP& z_N~@(r1esdJ`ircl7oVCT$$MDTf6d^{q+&1Gl!K>Z47($myf2MT+QA1L9OO<$liRx zmX?wBN5bO3Q)%!RDQjZ?JLFRSzX0;Q8{;r(b9o7V%_L}NO($FJb6F_gDJskO_94>F zUUTp$Amg)55eDw0TaaOF5wXqQ;4h?*8?MB^K|O@z!4E@^@pSMlGQ-`|SVCl-=6gK% zg*05zPgQY4fc<7>MRHF9PKmcb6*b!_tL0}+-2G%zh}~blq(Xp|rrvKh^eLN-WK<T8P&5|9>)u#VP{CVT(fjlYx#2(xoFzI{d{Cpn+6HMVW+TwaC=tLp=;Ct4* zf1gMFNc%ds{%G*?dt4@;|4StdI$vN6`;-VL3!P(lFF~Jz8RvSlz2>W!_m^dduE4SC z7#)_VM^T$F z8u*wIyu;+n3by~GrCJy_S94%gc|}y|-2X`>U5QOV@Qy&3K1LB0zwr8&d5({#;oGnW zt9*2fdiNztmZ3!0_T;mDrFPS0=H@OuL(Yd^3qEIl(4-?{)`IiOz)Y#-3>R(MW!I(HBo~^KuCH6^+e3 zoc(y`Z4UT~3vrdxE*Mjmtx>C-GZF+>$GQ{mm;I=}zrN|p33fLLHSmAuhZwvK|8kM` z9PZbVmD5BRat~a4w7pM8jV^@C9>nX%^I+QE+U=9*uXom%qrukP8_#WycK`uxR3qBlj&Uv||M?R^aq0B9xA0=K^7JCjdFtYNDBVz^WrV3A|i;kn|^O1C{v5_M1 zb2OTn6S}z%4PGY<{~=0lw>S0NL`_#gwB5YAzIgANn>vS6xR+@r$Ou1(eVRA5K0O7r zpYJ#dyC2K~NO-UgeVAujLLh+YG=YcW8ea>X8CR@ee>O%6gNFMM+kEc7rR+Du$CE8N zb5}gGJeome3Lq>+&#pP>@6)`6OtilwW1=NE`i%)vqrc!mBpbN_1lKg~-%-7FClS4E z@xyucUp`2-1g|!*hH2QmI}xfNUHd~ZHatiS?+6lJrazw?Lw2j(7XMA`IT_Dj*~l`4 zYn6{}G?kFDIRU!*)_{;@B^K9<^|gS3_-)G|@yWO-T7U1&N0H`L;>q!V5x2?5^t!W(j%f@jD$3htydS<~}5I=ru zi1K&`zyBlbQl5LDOI-6w^s2q?sPVp!T3A}zntWZ981;Xqh7D$ld6NYEX1RaJfqA|j znY@%fU*N*Hw=Yxov%RBDp6X4uuXaaqn^D&X3c>ef9Z`+= z@pus80!5=;hQHnyZaZ;)Ae`6zy92(rGpMgz zPAqVVNSyH?KPMdi71}ZB9Cg|*&BC(pM{(O;Q9ke^iEH}#YzVf_91S8TuhsEw_lCFk z@uEiSv~kHHhk{#fl0KOvfji4-DmNOxMIii;@|am;%>VTG{PyxIBAt*nQyC?E1yP=Y z;Tr@FFDx@NzhHDMjaJz7ed5jAqWt=!z}>r*D(Q+Nv~a${=t+m`QH6oT(8Of_v)|6= z`weu7p{1qwIZrG5_vHTDju$J=lb6ktzR}nFleMj_qqC(tCbee+p=Oo;OX~~M%i*gBi<8YXC7FJGFNLS-ao_i;6g=gehsUrM7|oq4!o;aE3jRS1dyeFC&r(;{CcE*i z{xT_WIZ=u!f~wW%W02GREa*BcO0)4hF>(Byh>V9J;5hYreRJ@tA~ZGk@6DT&+xvcD zB(8icv5VK16X!7c$I6w zs-xd{R~=Dj(4Em(r0J3G$3BX0fXdNiuDf67Fq@N9+cux1faajBk!}p93~~ZIzn>UG z3*Cv8`{9@HRO8A{-JiP=uQC0BrJI-Ii=_4{-ll`&&arK+4r0Z>d$(%m24DW;o@f%K z`{{-uf%Lh0A`S&v(q{{SiPC)AW@p2uYC)ov?>FUyO!Wg9C37SDr+k{Jo zDk%~Kg#8#htQAMxuuO&dbJIR21u6u#M0+PO+5L%^;VB0#oBp*gkQ>3AaQ`z|R3H2$ z%pa>iWqx0FI0j1t4EPtbaqz{myzu(3IY5~U=@D{aj4vk{j5fr5>=5YrV z)4`RV^YZM6*F;U1GOD+RAn9+%>^^$KW(5d)AJb{oe0?nM@RJx(#3%9rsK<>v+jj8J zembqlX6jn<2Ft;f#5dbHw6__;4KJ;JH)?@U&E8Xcx6t!A9T-z?Y-XPS;~1VG{w}Y9 zFkHWjV4w3lKdy6s*we$pp!h({%R)@n#jg050>`iM-ulKlHKCBhe2*D#;r0YUbnHqX zgyQLSkrYF>E&}m4E#gZ47#M?|bYYost#O>2`&J66Mlnm#ymP+I_#?UN{2dU%_~JC# zxTyRSWpefCGvLCg@2MKJH79&=?jCVx4~%mld@X7T$)fLRN7Zy~PF}k4+-UEBkqW(Q zG5OBhBrU0Xq|3^#)hL3(&52q1qnu07H_4;X1#G0cuB3}jaW5P+TM9;%it$*#!P=C( z=0$7|Te$q@O?gJpP50r^Odi2tl}Q5q`O3HWHJgKNqbbb#xJ*$9+?{DE=_GX)Qgsg`qx~yZt zld(;sJq7zdLE^&kF$qHT>0nDXj-J{>hM|rZPtZ||EfrReD!MS`)oUOGpP4w#3-KpV zFLg`31L6weemi7?cGqYo@bmk{_WP10-gq@T4UHpW%jA)Ny*ZO^9GYHRX%jk%!M}lW z6Jj|2`ZArCzE0d>@Mtx(8A~0osw$=LkOusIv|&G6j(VmBO3T8`JS0QV_VC>Ve7YNC zFbJy9O#Z(BuRu`0P^VB~D)b#J5moK5weq&<>eYl~3vbkH+wyhu+^rEZ7RsLLMc>G) zHEpyP3ffdSpv<}9)t5~v3?3@(b;zc^O@lURxeO)lJVVdbxNhB$#}%{^iQ4+A&JIa& zPd8Wamf7m2#80wUsImdqm6jzuS~5>rmP_*XnA9yOt}dH}L1D_?wAM0@)8Q2uYl!NsGmE9fo)eO=X+DDf4?-2*Dj#lhE5L- z_RMoPL%Om=TJD%-MNyh+%DYKp8-lQncSv@PBcPvRDO*?wb0#bSDnb$X1O}R>1PnV*C>Q5M z2Ke_9@(?LImk5v1rY*t5`$hGZWT_yOr)pR2-)BNqD_|_;WFqbZg1Umnx3Srzq)$3d zWB;xA%QfFu$LqgGn6wGl$?Wd`+upxNS(07#{ov9)#@NREz}RDq7Mf-7&oc{SU@;c{{cQbgEHkz-AOtKl z7#13k7$gLZT91CHx~uDzS^2zqUlC{i*n8g{+1-F>b$4YK``fEJGw+QXapIh~5ph28 z-Fw^Y)$(sX%JBz5Wvf3eoIW97`Fd-)BRoWXtYcvS{S-b^?(65RKd&NC^BkVk&+@dI zv(uJE`(vovS>d?lWvs95Bk;3E#`%d>du&#?hJeLi!wJD6@FK*yxrxk-6Yl=B{;(O- zMchR^)n#o=tq(gm#5bq26?59t_T7QUz}g&MrHaP|v$U`rpb+Fs~;%lh|aju&fs zE$~78+s3ZnTCY8mD-jU+AoGC3c{&4wF=LJZV@g6UkbeL4qf<{;E@Aq(;jl^Ig8&8 z{S>#BEa>IA-i9fzTdshnx01{`T1jYgQs|fZ3S%skd(s?-qLvG?ZalA~g{052IPxqc z%nC+jWIJ`uyy%my%Sw7{(WqQ!55I2RqzWKvxiMR=$Gm^2DF%`hvQk%KT2@%qDdv!M z?z*%BKIRrhorg9VY(bq=CbAW@0(B?mxmz?J)>7eqvnvIFhBHY^uq0m@%d43$ACXRV z1?(NwuvUrlv6Fqhx_>Dr0m@Sag{8NLWpV80x*_EW$7KCt?qLO+<`7Qp^%yLlHZmrS zZm-Ue#c`X=VOk>Xnbm%VG`QJOVA^CqJ74Ti5AIuRv(azP>1m?U*vfGQ{rIPfbBLu`?S6( zwSTKt-xRow!`5MLNNZDxSHmcA09xVh#&!L?HO+gZSi zRT(9)KDA|rt^PB>i>@c*ZrCXT`Njy4On9uG&2SHK5RLYiQ5^^+Z|Q~lkJ zUv!%Wd(F8z!`-YCJf^Xa96RUPDg9 z`>plZXY6#chC@^fQ{er`rOU$a?J|YF zeo^=JEFNNQSwRc{UDR#t3c8TpFbY zZQP}6w?8{Le7Eh`xNCo=zkbzbvId)MzG^%NqV}4qB3= zCs?o#A~4OyciNEamdn#zz?}rchCI?)PMIWsZBHG(n#VTJY6q}3`6>$;tEO=$vi5PV zGs)65*fG#8yz0H>2rZIdsi#?%N%DK1HZZJ7r@JskKxvsY^glyZsK2Z((}6;8&HI{G zI-ahem8X@RBhp$$-kCtJB%QCk?V#cMjX13B!N4rLlV_|>U@O9P)CjPj)}#U-t3m1e zc~rxqg!Z$$BggcGK1?!scL>Fi6rehokrqn{`!5^$zL;D1$*~r*Ec;f2Bkbpn#^KXCiZ~8T7GSn`0bmO>h9W!139Q0ZVg=wnO91K4YK=UGJLy+{5!< zTJa|fbFc6ae{&Zac%9--#ARJ}f`@wB49`N!x9~VSn~@p3G@y72FTk^^uie1Up%#*F z?o2E8Q|NxQ9kT^818G{z+dhx+B2xzVEQNppQ?#81*)s0rv`P<)c%D<6sT;VQ==RM1 zvW7cvD;zM|c!B2|?IW`z%k^n6)2u{?I8>yyE(5rB9RojhEXS)sy`+713NK!CPCsMT z7VAIjcPr+#g&z|MIVP4lp0Z(pB(2-hK1#Y>1Mt@GkLi2M$V_{P%m&AJzS#4K+w%qv zmLJyl5*`xY=>8w!sVK}+Ww#CnZw=(;ZOeLPx7n3`m22Tmw!0` zdwYBQkN@#M_?B<^mYdnsKlQRpfH_Au@YKwk$X93$2b|}TQ|jZbzs+g6jk_c_bp3Wp zC|m0V59lyw=_~P~Nss7q+X$#La67<@0vXKP(rvv83F{u5g&S8Ko=p(oYR|YTU497j z`gaz9U~T&tep#$^o7PVTUfa(DZ9nWe=CZccfUr3lzZ}WSxru~%e_Xe>jKI!H*Jqcv z2_CX;&qWO|ngg{R?6HEF>F>gCPtecXEzMTzb%W5Gc!~pi&N{*2p!L@p9;9#qFJ$#< z9A1{V)6!g|Yq*OQo|>n2r0c(=`~KrYcw{L1VSyRe{zYUw|DOl4o-aXi@?Hi${wa3` z?`c202@lU7Az|`%+jgNfUJoFbm^-yUidKJEaE!T5FX%d6t9_OKt!!gW$Kagy--EzM zTHCvaTT4%#GCo(^c)s*Px^4wDy_IC#Vo-|PQg7_@WTs~>cNC^UIS=Pfy&m~!+BVCut=FC@8_hELPM(^fq=6t;Be9i0JZ{K+IOjR@RgfJ-YXLHlDdMm z2$J=c71Of3u2xtn%kQZw1X6071db%QF(vO#Nq6+c6>524r+Tb`=O!(+f2LVLb}kgE zDp<4>6Wv1c!qypjCHd+|AnVzlK=K>YxeMDI(3DBqwm*|L=D8r@QV9 zR;O%Qs$_c;0k3)YKmd20rCmo2`EVxidQwAE$$o5h#l^g_2vtqqdy=!bPzap!9N?yu z<@i`C=Z@PvtflzdNl-x3&@<5hcS-Ky;o7UXWyAocku67oWl$1%v#&c_$+50X@NUem$dDBtz|52fY~Un;jq%IJE`^0tSkfF=Y0fB zJ%)#(7x+xl!m!O{+QVm98JWSDi_*ffsw)Pk}H5aTM8|EIiSjtVjc$ggzZMUcO z%WkW!BRt%G4Ik@8eeEU4c>aR6A#)u58Q8D1EsyKxj}SO}hkj-qFE?yfAcM`fX*(a* z?PmOVTEYum8ALV+Yjz@=UEe^C>4Vm?<^+CJ_sv|{i^vSOtAE=}+w4)+@Af?~kZg3~ z1`gdf@l+7@-LQY=J~mi;QuI7KO`lDD>$iR@ci(+CuX)XDSX*1;cYf!0c-On$#qGD> z&fobve+Q7s=j&hpdfxihxAKEO_=B7}b&7Yr>s{oW`A7fgA3Zk>3w>5HIJ$$o16TFE z738b*Q5@u10Kq=;^?MltjLe;Aq1Xn=?D>tI0_`-op}!ma9OyReQUn4oui;?JPPJzE zw<1smc0UQc>{o3wz+!bucL;G3gB^;{nAt3P_aMu!?J@C{9*R);fEd2Nt2dC!X zHP~*?z&?sR+ZrKI_ICaJ7IKML*7h2(M%#DpJTQR|T^E<<4u09OTdONL@Lt1jEw1Rl zv%1Z@WL50q$K5)T{-D%-|4n`GuK=l%EPnPpZe5qz(LSn!sVIIaa6599ZRPO{yS|rldhvfaz2qQ(7uzU#?CxZ(Sk4&Z>%A=y*oLuKNNS z^VJCykTxoZVg_l8LSUc)Uvq?#-Ca9u+^y3|q&0OlYWs^j*I_oL+1gW}t8T!JuKZl; z2mn2*!TQtys_wtI1tE3PJPbT_3sSeBxp*Ywb4o9hNgb&T0{lA3A?hgmIMvzDax-(% zCU*u~Zq>ahEOtnP%H78WbEhmx+c{BqX^_-pAiG=0KXXLd>m5B-wrg@XJJcJATbFSy zId;$WeSMl@Aa`5Ip9?*n&E;#rb=t`C2K{Rt&l^*Li)E5yezhX?3Yy190v|Vfu-uX3 zB*`%&E~Sp9Dv)C(ZT865C**@#ic@LfFYH)u@S`ry)VdND80J{hnvba5S*I9m43$tFr3*#IhcjN}545l66 zuoWD1TG)E~x@d)V3}W?=S)9$-Y=&p9y!Ph}4$^wfK&II}EM0&tQ|dAXo@Tf^-k?u| z%!(}5(Hyo5i2bBMW)9{S?BHSVW>YeUqUF9kM4;FRPg!sokMA_+>pE^Hv1d4D$1&iU z@p#NBZeN+;aI%BUcGhrUXy9>%%u;W|XI17@we`&O{fvZ?uk+N9`7Qj|vNoap^-}%Z z5)M$u$c%au_yF$iHK%c@>$2IrV+T1}-4~ux- z&}+!o^1Ob&!LwvonDeN$t{Tr7xr4hE_wb@oU!t#l5D)#o4}a!kK-O}qf*buSUH=36 z`z8EzZc~v9`reN2hn2d0WFZ>le#T)_4c*>hX@FK6`l|E5D)#| z*Zz2guIuACJgv2_KZyX%As(<|m$WtD&#uFbZQ1!3-7ar#4B_58fpc)5Z{Lw!ZY{l#q3H|#x)sp$ z7E-Dd{B$KZV&0!g4#t@jlS!?r=jPPQDbYN3Byj6g<#5lOoK@B_DyI)AX!RMS^UvM=$EAX zmjvqNmJ`;1>#&y3w53I}=qU)a{kQy^1|91e%_nvw+`8Waih~Ymp`iKXp#aYYcR@C2 zF)MW;jx|L>H%VU9t%=M*?p&CMs?V#>j}?9v+Qvp+Gnkp{EGc9QBy7K1$o@6i9jNV` zr$w5l8SwmltuZFeoua7oG|$x8srgw`PhG5&Mu4v!H(6n-wJ{|)Rd}Bs)=)!Q>WKSw zB5h2a!iyhOt+s*y!zPn!NDKNvz#wteg=XaYZO6jijC6iM!1?Y>+`k6v7Ya`^FfU?N zC=68x>0&wWtGqvxwzg&A{&nrSNB3uQGcX0@VMFr=yBs`l$kMBp;c&+E(unStY>Lx) zqepXPB;b5dI>fD!lnPd;Ox?a|qmsjZT*GWe9wpLhb#kETv3woR zV-Uw?2?iF;VRr_HkG38w+SA~n!3}<=exvoe0UraA7E@>2sB!pZr+ITon(bqPz_nVp z{U~yWeqLXQ{JCuy&r!UExKy%;jtQeFGs02C9oE zt>56g9dCAQJf@#9FnXZtx~;Xm9Ur!h0q%e`S9QXHtifD!Jezf?uj6?RPa|O80UH;q zUcZJHt1=h$06ETVro61{`E_0I0iI{}imu;Wrh4s~JCmmft+3heIgTgLJ1KerL(}j6 z?(gQizx%uY*yYyO*LnB5-_5(<{qEsXtX4}AS?o+#L4e@7uBP5OGgUHwZemt+KT^4Knlr}}6WgmE*?!zx5j!%2mVs6b1 zB#heJjJ8i7#i8J3{oS(EthTmUBXH~-0^Tm`x-R2j(*gtRS!a!$VlLy3Tzl4Mz|fqc z=kVuv+q!Locz1E!p}2tqPkX*Q)%V}1+kX@XjF&i`@#Y-j3^w4}<#-{gP25fVNhF;7 zg7)bqa=N{UXS=a|-avloZX*bq?x#J|oZyAB%w5cj;s10+kL6|E zSRYpIMsgKgkQLwiU*Tg9%9stg^<=jW&-FH*3%$^vN z<*2K(z)EvTE_NgjrU60?MVBx@bwlpX1n_hcbPAs|*f%R7ubUIq@^PyB>=+m;5r|l# z73@p$Xe`Tg5WqD_#^4)#aLokVldiG#}K^FC~}h(X3UF zBl{${ohP&4cqR8TiQDl&`gxu&ZN7Y(udg`Wb;w#403M-C?Z5jinIi6{OpG^8#mS-Qa(cV_~)OB2m*kcd_PaCUsleC=pk-^<{woQ+v>0 z=^z?iw-z!JfUKQRH}1Y&C>fmXNUDIv4%G#5zot_al$!FPT?B2?hzqw+Sl-HOnnw+( zo1kBjZ%oMtQ%y6$$xwvnhn|UQgdIaT4?bhNhtxw#*%BnKd@`bqgupM^5`C{xx35E1p|$z&-kTb8><^ zPQe|WcB$>-aQ374vqC#nUBdyWwZjbO)|NJ0wM(KoWZTbZK7d!Hx94UCYnOGO+oAI2 zh+Ia%;Y8SUGbE$gEJa*5c(f!`wTl)Q%L zb~OiZU)OUD2bzz!`e9w)w~+A~KV5h60#gRh?R^W8e<^U+OJVCl0htzX^I{xkvk!v` zCcg~bH)%(H9R5ECvJP|0qTAiTQxRA{wBe)$1Z?1L-N%tJue2|A_45zlDI@H7vRi?% zE^DFucGUU~f}PdkO?1?aw57%P-fu`L=-mT{@!qh7y zf9j<1u=pZLk)l$aoP|1k5x|?e0^z6%l7iIKl~fA(npktvO2<YVK>VDFR?R)1|w@uEeVvfxwy+vCh;4fp?z+vW3RBJUjuAgwx{E+Ffe zG}I3;}0WZGIbfQCeK! zIpn)zK+;^72|urcTXD=uXwb32L8Q$na|)ZVtc_0gx3k6S^0-aTFW} z#MbYh#^W`u(#4*B<}4l#Zv~QUwzq)Kplvp7VfQ=w`#K(LXzovg*pK1PM~lgvw$^zS zw<49u%*$Z5r5&(vesgBpObt9d-yrN&U5E9rK~($Mo;euM26wF5F_97HZWnj9cJWfj z7S6xaT9-lKQh!Irdn=Chcx$_6BQsa(CNlmzI3Nd)%|!QoSNq9smD=ri z6!>BU96ydj*cI&~gY{+=GQf*&!-zx1o!|ETD>x2QZ?*!OhHjGfk<;KR$E$lApyF#s9YuYw*P#z+%@*o#(o}OILJp3im2a&IevV$+E-9b525=TNTSn$?4&)D?6%f(tLTO7G<~5fpy@57ygel? z7UZ27`No8_(Q}y7KuY57%Ud&Xpe}VN?p%;UI18mL)9pxj@T}!@G&odhxNh4p4rt?tkO41(8X%>jfuUC+lI#S?gr9&#a+SbCI zpPJv4ULnx&NF0R%G8O7INbxQOXlX&A*zSz1Zr`~Bc$U?vDPxnbO(b8Zh2m@Bqr5vM ztyJ<}YK8hA>9`I`S&tP`(k`b+QVkw;nzm9Gq=djlgO!$g!TP1ib9ZtYlmZ5=7}TKj zzRtL_wP`%O9~pyYdn_)|M)oxgO3k^NphD74>`W!!>!1{HuJ6zDsFrDd=1;vsnyJTQ zUhYU!tjL);Y^RO5aV?F)!A#bP_CuisnKpFXv=CIDWf;}uVNKqfk}n^T7fL!`w#ofp zvO#n4NKzRLO7fMlI8N6p53g?*|5E5YPh+7e1xUJ&l|c5iT1igUlc0d6p=Tm~P5PxxI@iMa3D z#gN(n$lzgv7vb5*LEAFoGDO>Jz%jQzXAsreJ;NOoJ2)gXnX}KJn1$$@Bh=b$;p%HR zSj^ha4l*;f!ap`cG-u?Bu6J3N9pY|Y1Jt%JAhVT(%%-h<``T|7I=+Y(d}@cTpTg}g zW~XS~4gl`*wf+I0)!FsE!t>o49Jkq?%{bcN-1f~t^NrT~?d{mL&Vb`VYkRjNvolN2 zu#LE0`nbKu)}M4=?Ks-Q;jg(x+i{9TYaQLzYu08X7zS;p9M6ZlipPvTrfs~`YTIsW zJs&}0ZeNbi^6k5_qkUrz*hbfV(Ap;WEO&r^XYKoZk`&N1bdz)mPd`0CpppSm1Dp0N z@E+WiYT$DRccqqiXtaIJZMg~VHeAzX?6foYjNm|Pg22aZeQy&1gy5NBz@LNIv!(V| z+dyoAhm{*NG>4o82wcWbL*_cQw%I!G$DN|>eKz=4={mj~&(C?G)&3fRp9Y}qd6tFW zn`^R09I6I^w{;t@(LS*@+cUwwu6J2Ka}9rnwXEA4x85@_ZKuOc{P`JpI))(v5m%AR zOR@bRLxtyS zwP%+W9Mjdd?Q2`s@bnPYN49NqliIDr0KeR<>A!pM%l!skqi{=?{SfdK`tzQlU%sws zn?{cU{|_0fi}M5VHj(ELi> zqvJ-LkPU#kI-3S2nY6M1)2S4r>gZuu*H9EBgRcqFaz`MQIVY!CT#E;Kcis_qV_NUZ zes_|DKO5+?aO`QrydaXfXf^jLISbG;XKcpvOd70he=f;-^F-S?=#W-AY_%UV&UzEpwF`?ZYcq?U9HGaa8!IftCb@{$&XjFpYC=5@{cH5_WS`BK+C%cQED zJ2Xk^d|eQjnTNIH51nQoGj)$j{!cmPn#V^ppW2fGW-Art7n~Bu=$S5QX_5T!t`}V@ zOGpab6*lH^BmIAUBDqT|EgrU@eYZP<&901@Ldkqo`_;S2;()arulBQ&{>jrU4<06s zjMLtXyfu-+T01i49Ly+gUxd4tq%ZpmP*w7N(v$#NghsONecp<7GlMq9#T`ue!j(C+?Ugagd0_+9xn?zprZl?JoG zVUdM`n~kNwV;T)yuHg`B5fAwv;e~u?waZ+qrXCK4%o1cF-G{pV1>M#V4^giXON&82 z@M`ns!Zg>aJ#4bPo1ND3Hp@&nfHh!ckjviN!mDDKeaPVLB_!YF6bEnyt_`sDbf1R! z>}nr}*S4;N!?h_gi?M#PaP}So84cQYa9D1Xz}%zO29r6DZKi!0KTotl`f1!z3dh0p zCIT=!t$${rLHo*_rxtR*gu8NIhFe*75HS8R;J1O#*JUr^F{+juv<)il{AoE;Z5)jz z9O&!jg0+0O1}e|#e%ct=Ljbcz&2YDBzx5e&z%~dBoj*+0*9@+kbJrkoJ4V6UTw6T|Um~=XP*-_+}is*=fumc7u#q?3+AbczELvZ;Y!?~}N4$eQ~c}_3uPlKr7&pg4O zbsEsNXT}D@mvLxo&tqSQ=S=Nue>~pWKfA>kXdgbVpBePv!(%xHEHe(;e}f9vrpHrE zJjSi1fTlN3CuGJQdN!06N}8(^(ppylTv-S#>J-qC(B!n#kz9=3f^^5CfU0XFI`=P= zCyls4)zy%v4f*0Btaf3of`geWvb%pI6lm2bl)EArD(2x<=0LcnXzNO-on z66eK?B&R8L78p6v@cfmIgn(zn)mt~@-Ps&^lj^UstPZY!+)ihgU zirW_5&1fkTG;e1r1(m1__R0DXY@vwD+ znik@{tLruxX`su%m$~|EMqprd9glGYFS~0H6Wp)&1<;rrPBA7a7b6-u*~+|_MyOGSUW7+Y)h7l)0~b&j?a$wwO!rT zI*#y)_cg~I#%;%}K~J+jS*)eS_koY!5;CqmWaig)x4sxpEQh|gjL!rg()FFjtvhCy z>Ebz0&2nR4a1#N~pTP6X*0@vE#`Fk>um&UTSTMJ&5s3ylo)3{@v8&6PyZXtO0&|`A zbUXV99JYr6Htv>M;tF0IZ4C$S*R?H~<8h?sxV48K?VQ5)oji>|8Zzoz>-#ev_J{=SYI{qJnG=N!WFHW4U%UblZy|Cv$V zPLl@Z9>6abUH#kY2=3sSSze6ics19k_45{fDK^-A5doOs@X)|&gIrGS(r=)-!a=h2 ztM!2aJ#zu?==)9Uy-nnK+#LwC-NAwSn}AoJ*3Lm1zi=OXl@9i=jb%OeBcRb><{F;9 z`taY$dj`TU{x9k}eJx!5MR@QRJ*Tc+rl)wG*|yuZkKe8>;;vfT-d!3pP$5^ zd7A6FivVbQE@uwxi`rig0be@y>^2YJ?&sGajo8uU4A|Rk;jJRO9eA#{5qhdl$c#Jm ztf(p^2jUP7FRp2JrUI@smt)?WN}khm3sOP6Ur@esO<+)&1jHTG9?HJdk?{9vL)z#H zxU&#A3+V=*6j+g^q<~Cwnx>)2z0M-IBt(Q4KwX zjOKEzq+m33)W5xNn(!L+mPfd(6DhRf9NPUshp7 zqXd}Z=>l>Vr>}*Jj~nt666n!9A(#KO(k0!wAnmM*xf?Pc*3$O}T7`bKBM#3}q1v#P zJhfFJ$4Z%`*w^+1mP=>~am4P=fT4iS>k~L?C{9&yst3iG{AqbFovH-LZ%ws`R1&8r zh&$Juymd2&#<}fS?zgsAXdn00DXTeQ&25~DB#_gtSe-)L+?zdt<>Q*-?gc+)iX_0Z zK_Kd&Bp)1!`?ueb!eocFY-`jg^seRM#}gycsY;H|Q?0Q&swK_Bp0qO`8O6BC3TPU7 zCbIZAi}5pPI>eo!69l-Juj_heNQ~M#K5JcVwclpn z3&;$xLM%SZ+Lk@s=2PHBpxQY>?b3dTrwmxrbv=U523K_1>v$elb42FWI?aOA;Q3H( zwl%_`t;G}COs&M-z*e|vh{Nvlcp)O2!B)ue@*>=YY%|zh+(EgfePQEoV0Ih$JluJ? zfjfN-c+ZfTpt+Lo$DOGkM`m$n5sS;AzPG5`x1vavO2KCD8?C>Wv@c5i-HuPQKCR(k zv&7w^MeCnR>ryQOWfTJKrNe+Q3sweRGbwy_O*r$`Eo z0iF==G$%&^O+z(&x6d7X(7=MArNke*Ng+d1n=t4SLu82$8&gY;#JYNIS%M9 zBB#ffAs}xD_@J)$F5QPkKXVB=g_`r!>Ie>Wncu*lOWD4gyB0je{tEt_v)}r6 zQJ1rRvOtYB+^q_7DX{)G09&-)?;`;S2Ks&vcb={zDF!YeMV0I{Y5>sMxexw;Q0Z3v zDJZ`Yco2$@dWM}{+{Fy=j=K?Ryaq4%3&;Vt0Wbe2+OdBDh98z~+Vj~@*S7{8`;}`#7>&gMEB#K#uWR`}w@~=SQ{geo6oSB<}n*SMAR?(k=tx z`?`)>Np_p?TyG=vR0TA>l~f?$<cW0Wzv9Dp- zmY=g%2%OcF33=2=Ul`XGuO&3ixHAAl=@>a^RRQgDY}|lx2y&F9zEBW&d*jhLw~Nf5xS-H1mb?H5P)N| z83TGFyl_(6X<7h(fB>3-{#!uqmJRUi>hDXf^%`IUuVP^i(gFu_=9IjFp9gKGVBiS+ zkhGBUBmI3}-!s?eDjq6r;nh!Q8#eK3>*j_v7-s1KY(ECbOv7N|DLhrdmbT?Q?qpp; zW-8`Vwf;1xqq!LkLfWjmi=;uYiCK*l2I}B2)cU|?(`(vqS8#x8@YjH#_3;F^@+92- zY5%NGYuui+g3NMj+}+s4QvtN|j?P;BlyqH|5AmW$26Kzn zer@PJe^i(4;kjWS(|#ygePyw=EBLY8#mh2VKbmF9T(mYZ9^o{_jwgH2V8@hwhwMRu zL3x9ykKo^fC-gOQts108KfkZ*G>eg0$5wIJXfxf8?(br2U(Ic5-wOlu=D0oy3TPU- zi7F9Lx{W(PAHj*fvZ2)GvSLOnco-T&xjtt zq3j0!oXIZ9=1$#2PTjlsCI1{=(S5nqZjejnUHZ9;_$3LvqWmJq3stS-DHF_`Z>LU! zfs4Al1)5lPmR0@ihHk@vxSissy07Q)oU|6iV7CR2YhP>(;q!k>d?b5gdF}T9EXRdi zCflIaj)5Bw!>N0LU&pI-HNeN=w;zKq_)Y2CRovOUi$l<5UH@g=!8yd!hF98OJ^UH= zBf9`Zo`yd|3@_ViREp;9CKwuk(xi*D|TdxpQO@!y)ECn>Z zg_K8HU?>YPq*r=~dC`Tb_rDY@6#NS@)%(I5Mk3 zoP524Touy3M-D0O83-tw)y#`MwVjm;u=3ta3i4=Zx;Rq1(CLu355*}s@n)0`NST@tJle&Ig;^MF2(VgH5}gB zqWvl9ClX1k5$A)fg|=#OaxTiTnI_^W&4;z8AK2*1acV`d3_!1RB=tasd}Ah%v_PEB z8(ro(am(a+f6b9RW1jbwS)QjSu;VWE`!Ji5C(~BZD+R}$;(`J_jx(-|G zZ0{3zn7QT1wEmhPfb$A6+d9MX;zRJ%JK#m!hOvm}@ifqD`>=vTuRR=?TAM5ftO4sI z-8TbfwD!Xsmj=&lMtsOqXY@9!NB8*#?hdw@lsPpMUM4ugUr@!zxVK2>>>__Z8ki`9iwK|u^7c0 zH~?+%+@khcU$?u1k53Wxzt|L&$hXvJ@0CCpFVG4Gr7d3s{C6aje}K4q%{6S!T>C7Wx??{A{4DTm@`3JSP>-eUk06)-E4rT-@cg@% z@k`=V$91IZz6(z$aS1;jOpEyO)OHD*)^KO^n)dBAUGBs9ac8#yc8q}MZ+%Gn%lf*# z{aZnX2%hV0gr2ICbo&zeT%}+oomS^#zmPnlRurg6q@{|qpf0=;EN`exWJ=PhMBW;E zv7+?~YH_OOjE1%~Iw@$mNh=MtF3Y)_l#znevIDcJyEe-t&cm7HFU`3Tr>W&X?RM1x zsWT}BMX6VimMUpWBj71%$^izYxJVBq%vvh73$#jQA#DPzdVIb*CJ$$lqcmr|(q&jG zVQpO?-_D^dJFEphS4nbu){VGFHB>(Jr5F;H!?ex<8c`SLOp5#DVNJ1C$-d01qo+A+ zojX1)f2Kjb%Hi@n{87X9CH%7%*gdKRkS>(shV04sq^gkov^x`V#e$y^y9$cSQUJ4U zyV3WGB(U?aCY|cdL8d@c=FU=PdG4g0SFaz|bGVxKr5IT%bUZUKQ;6E@(fNz#0VKV^ zp1|R>R!OD#Q7S9pN87)pj<|yR zg{O?reaQzkd1orn)N;2b=Hd6`EbBC&Yu_asM?2=5#*d9@qhqJ|-JP2&(c;;bZ~)YBJSV8- zJ+-e$#qsd_DLxai!bVnf=?NSN+UE_}S>iTu*Qq%cts=b1&a>@s>6vb4r0-jCC<9<^ zKxYs83{qO?bJqPi)PJAA!^YeFx`@vTt-V$Z$Y6A(?K4;99u9$RTrBryrLS3gEP-5~ z<9SeRzisAc`(%*H_F<{Dk2Z5{r%N!mG5XUAVA&Wh>M~|eGALc)(AxU6!JVnrM>d`V zBy8Q%3~b>uGwWANQ&8*neiNCsUcl`x4*;(RK7fa%+dB4jA8z2_y+me)HuiQr*}c{b znYmiu9pUcJQ}~$KK2G%YeyhD1Pa|Nzn=Q;{o(5D6j@tLl0QXv}A5v@Ghj6|Hii0)_$v42-$6ccG^eJCD1H?fKyV&x=~&8G!CWPNyHy^?ek-)b8Wi zdaSKmz|R1G=|954Uq@oyEA6QN177)s@c-SGb&qj4Zf?<41VnD&&QR+YaM;<`_w87k z;^S=T7|aP;YCF&C?}x4T3}l<`z%O}=c!4W}|F$a@u(7VMy*=MrC*g3K-aG{~y@ize z1)S*##3_=1yn~rTwpzn}Gg9fjSI}G@3*1^PrE2}bOk8}mx-pMx$%AIP3m^YhZBK>OC9oL;y0(tJ@V0P?yyXS!;n0yNu3N;1x+JxaW<1M`y@av zPaCaRUx|zGU?$=A*T>|Y3B^52q(OHMsq*1e_IWIYuCi8tPn$h0poF+2PjyN6-UpK@ z`O;(LeJOgBmO7+0-Dh>Sg7gWUB>719XHtMEqwd~X3KUJnHJJK^{9PptgNJz$r*R|c z3?_}VbJPe3t+Zd&1)LU&d8mBa>6sYN}uNvdWAskLFo?FGRd)e`ZUxv`O21n>(y!wTd`th zAjhWVB;BZBSO^4P?g)4+fZeI|*Zxe>DfA10krM&p>AnFh=(u;%JjC9@>r+Qzw&h7} za5rgRKyAJ@lrc^Sq%Co`EBbqbz~Tb(<0JY0j%rv{&^{~VnNH;^vbKf#evR#oo`80UY2wu_llCHz{D&=uAa_Q8F566zB)^pT-*Kw*x6hVorwXSsqT5uCUV^ZmBfjQqf)_?2@P)gar2APR;Bto--$ z5o1#xCE+^VpgQ(uI7$;wo~`RQDsiD>Z%|oAx*>upse(@}(9j&bwsDjDF*#(d=7`-kw>VVYkyYne_>ei2!!4>n;FH_qq= zH;Fr^C`A8c%2q8FrbDUx1hvo6LxkgEYy0mnJj{ntGTB40waeRLBDB0NH%db-73~Al z>Y!%5tprU!mV4;7Y7eS`7A}9vmcIwI4?3dB@Bl+=Ky!548$wlcfV};}q9<$beet{~ z^2ZF3;Xih^U!8}$P`A0emNH6YMODi#keyj44g4djVMa0k7HxSWJ9RK1T3-X|8a|z1gGr$HRNvI zEZD^bs49zMhoIb%0ndU}mTnqD_HVsS^ZW9Jx<5cKh_^on(Go5iTxh%@f7S3q!l3Ps zfG^JKcDt9?OKm@Q!a66TEq`@R^XbAH%TArjzX?ewC}y;(@8mu#l9_J`J)MAi>}5Ta z(}fHx#J=>(Rfa1P8zLxB&*uJws@@< zn0KZBD9%F{Q6JP`r{_mNrx-Eiww7sv4Z=k4C6^HoPfaM^v)PH7i{y7igdmv$#-|jFvX%D z?p4{KDsiT^&sX+YPZqp*Q!#9v?rmrqIK3|cu}UzWRHwY5Fn}LB-4VNeq5G|s(tSrV^W!Q_hJh_!GvE8PwcN;?o$%eGoT!p%(KIhX zABo1$+y-*j*;5UHoJw?tX?}kfjg>>3c6dzFTg!axE+MDruVTzV2_5*!*5S_AeIj3W zgoSs8Yn+8Crivny|2rZf!>7{Lja)ryef9+ah4bUn5N7DlFuB-bTFF6mZ_R$sAA2yHLM-d`+O!)Jo)r%sZU|FNAk2A~k z?wYuxbF&x7j3Rfl&0CFU3dt-Z=3F}}bz)TZ`2>9)@cgcf03`BhV;Sp4s znMVIIYxZ?yTsm}42ikwuoo#Dv@erb}B4!kxa$4r>%Q0IXR)$CjF`ZiAVLK(?Yu0a; z4PQ6iqdl!|zoG7`zI-Vi+EjfXpn#3`nyw@t8zrq!~KfeYm`q|zaEVVRUbH3 z1RCPE3+8gt2`og%E>%7sFbEO5OpOI5>P_y5eiM-GEU&96N-v1VeY}4~H{`nY%ux2# zaEo{xWjpN|IKB~yGLDOk8c}3e3ckOkLS$7Z9DJ#peR?Rq$qg6nY+h=bLZ%rgmWdLZ z4|zGhp26aHc7z3IOGe$YocqPLLg8}%Af@uEv)2ueS@sra2)ziFA)uBaIBQ3{6NAyZpN(%_ zhD$_DGp5f3KeksS9DH7_X@!Dj`r=&2?@vnF(Y(=Q2&bJMxGay*?yi>OcaB&Q1HEpM zvU~b#nw@dd+_QdPKRN0WO0(Ve;I567h3NnnkpFscNzY}p?E7sFPc zw>K0o11JdXb-#yneA!dus6EqEMeAUi7Q=HFuk1e5F3X9sFWbYoJQ?Xvi4o-0O*R0( zxR?6fIn3-jmO^ryYkV;Nu95@iApiKJJgm8kVe5%uRk|Fb{8Vdn4)geH5MPn#FBPzj zoM&d7@>TtQkPjEqo8JB*6Wh!@_=)PM+T@SDapj84&C=S1nBSK;=Oqe1WFq07DJ54CgQ-Cv%XQ@x7#$fQ{jGvd~F)iTkHdgWD|U#jM?5MRqHo)b>}5)TT+`#`6h+gM`Zdiu@fMFQo8s59nH4f!{_&VO3po^n9oQjtgDFq4f$@yM>BPg`aukKt`gVdjw^7|PqV8n zPFvGaD@3u!OjbsjaKh&gLV`(nAPX~>N>@Y<#>h>~--uYj!*A*!KaSetKe|Jeyu(T+ z$H}+xT3VoxH`f}rIzR&64I3&L&zu5{JmDXKHuxD9c6rWLQ<9pD&FDD(#?r(n%{K>k zk#aFgb@L$avRo}KOLK88@e zwpJ|uA}W~mzP+V!ufrGel@LlS>wV1T%u^~tPwD}j<--u89|hr#O{rlAgOc;Yxr+7< ztM`E=tE~+!Z&9bSO}6~Cegm^OJt*SYTiR7(_Rz5`F~1VHN`IdCIg#19c)U4R69UN0 zwF73CP^y6IeAj%=qnY+urRQ5$CjS2HdCoMDi6e0YN23XPrBWRVj#)Ea2ou`p^Rodh zS8d+b`)W|1H;>B=#i!P`_MUw5trh_VU^Hd6O5OgI>*%gP(953N9{<+Yg&%SFS4Gd|Fu>5>`p>s^ZRJJR$ zo}atuFzGM)JD*-zON_-cYq{6DYHzSvZ<{RmpO$23MehKQXS79ce!Tf&NC%cjM~KF1 zQ*_R8XvYF;=gGnfTQKmSeN{e(`Ps1PPQ%1SgA*EiuKi@b`V&RLBNpOkSKR_HG6&=8 z!)mnaKaZ|+=(xAc>GF{nELOz?&8v3!}3S+m9FBT$x zotDWt1RAt`6}2ZI?7#SE=IhjGh10pdG`zle;A09+XgFd@zl#BZ0|HrBzE)sPy0J+8 zeHBpKid0_zbFDfP6AR3!-6G)(q?Sp|z?}}@gmTP63&&|M z7e7E|S8uRP82%&aEqONOC@nx5Wi>}uFXUnc z7#ugS+oY$*$uV^=v)ag2HF`3~bJv-Z6n^oleT6YLODsV%V(KE{l;596H^M2hdfb$STw_)A-oS^bBgvND>hK!wXo_`JEu2z44-LemEqx_Gm%G6AL$V(- z?Y{S;vgcRd(iEiD`T4k5Bc=pm9FcJ%O4RnM>Q)6Ue(h;L6eel)K!o@tIk*#J&wG=~FiGiJ?@tRR`I zMI*B@vE(%JfnX`gBrI}TAKH9uDI%@8mt;`N00Y6n_2?+kJBa~q9^Z7grWiW@hdWV# zwLSLZnjB(@UNI-#AyEQOU_MN>{V0HvmM9U57opv*?lo~i6N~8pTz>IuTsf2nCR-74 zkSs`1*xN%8v~NX5jKB8km5X<7+QYnA9VUFybX67PI*Y@f{DwFN`&-QXEE(6fzxfu( zvz0ce73iv*O|sCw;P|BstKN8q5wYE3G{HhMVr+I)mOwd;X)(&wc0XTjAWYp9EEwfl zlfT~Y;Mdy4EwTvJf@w_H2g5)+TgQel|islD#A^X#go32a( z=jwO(Q(=2P=0gSGaDOkc_(YGBi+O+z(^DV?BdSZy9x#(^T?Xys#vQWQ@fA(Oi>dA? zkiz3ZU-@==s5QR-hR4-MK>3V64^cp{H5m)ETF5C?3ebw~b3&>r_a85;-3g)!>-I$3 zAH7EQ@E-rBMS?^?j$LAB6AMo1^H}G{7rv@OFuR0FhLoD&yz%8}1xaNV&`7)a^NHuj zvTcH=hZiBvPH1yY_si-dPM*{ryuKs}UEvbayoZ~nG}>%dgobESz5yc8V?|(pH#TvL z`Vt}HT*%=NTkO=dAQIKuDq+lc%EKRMxO5b_1Y}Yss z>@tS_yt^oITil$QTm?i z_}-Jdbb(M&|64yl6JeLu3&@Jw-j|bNf7kIKcTu9{X^~PL76RJo#wRuTdsUP3q00=a z0s)3uK>(`5?9hkQnTnC*w-uxXS!18q^kI0#PZhEjXo<(fDV<-wHk+xE6g#t4VAN`= z9FU_ETIQ=1=C_QQr{NmR{oL>7dN~M`LiIE_A7x#y*yCz`ax(eF)-2yyyQ)hUw$HT? zlE?7@K}MAY^$ebBw8%}?W_2L=J7$-m#jM%eMei{az{hf?nfXb(;;TTkK(L36)?nti z{%E#wj^#{Ov++&0CFog8N4XO0h{fWKd)fP;Z(q3uGM_05sz~}Wv6+EgkL3}E&|s13 z{mA~QhJ;glBR7etGzCufDQ){+@V06X<!n|* zMCcB+{r+gjj^mEppp@6_K{TtjjkJ(<8<81r)!@H9yQ5z|EVG-&MFxT7U2$GZ${@c$ zX1oV3&I3AM(zR~DcTk4{W}nrMo>nLVTmiXb_;wnZ3EUV&p~UZS6$axg1V|tF$l#bRSAaY3M}~VZ*5OiWOTSs2-QOBHp?EAEPB2F<>oGgjm>7Uge4G^@ zF~#vGR`*IS)iTT(!QCmwLGzg1CaLAk$j|faBbuyk70GUzJgWYoY7Jeo7AFaHaVptT z9>OM5nhB5PMM{t>c~&1XB`Ormef{ZhWSEzKD)TjX@wGZ8O-*GN;!3iP6`2!I66)EO zK{5QgLSeRYc{R2zycclkcmn5R2%I1JiA=MoF`Qkf!BN%0EP7^+&} z94Sgxfv1WZMhW@5sUacMwF>evqO0?#eZ8owr)eyK%h-yrUy~b>LJ@m~n#j#8kXgsO zh!Hr#ZMh+l1Wg-2%}$fpb+N%Qg{ENsg{j;J8^_&tN##b(9f z)5W&~=!6C1X>``Qi#v44EDR$_9~*aEjFQK{HqS>E74GLgacSXCN3FcvJ@EVwImh($ zJ(rAqDajQ;!3(l!Li6fhp0EoeJ)?vNI-KWZwyv>DekJbOzU4vmAz>4VcXX1Ug6PB5 zvauODza4}KW(X_7R>){zwT==ePx@ zGt;iHk^sMp%pV|Txlr!ifUgsM_)5G?2l>OMPv9yUYDxC2-a!HyM{QAy zk4qolQLi;P3s}y*3eONWrGLF+OQ_y-v*f=G?r{)v=4BL9gSyLtOMs@o|I{75sy^&7 z*=o=O)y@wmytP=gquT~KJ|^DuqY`F8FYff22#qbZK_A5*9JDkelA^#*r;7&@h0X#e zYUynrv|H>L6JvTFG#Y0+VvfKemsR1aEHN$Mkjd6XO>FI|w8Q&X)S~ZBcl4#=M2(x` z{@bUP*G*>DJ#nQyL?3jqOy_T;&C-B+NJbl*V#_Go3KA&bn-mw~LF1sFG0lPRF0TDI zO$@~8+k}KqdBmpdRHjUU@8Faq^svm3o)p1BA}3+i&WRKt{> zLA$mLMpEt5$Bmec^v=OkJPxqGCa3%kPd-)b1xJ%}s^DOp;J7g;vTn26G$Fo}Z!DyL z@g;Hs$ip_Hf+kIS>Ga)vz{TVy-Nwzq)+v@nIsO3Qh}~T-))34WFUa7=r4dgWI}}3; z)I$w`vc2#PE#(cnj8kM+5}e#-Js~Tu*wid-vBMe8pByP7sW?dxo=$jB27C*UD(46< zC#@G{;O6a(rJm`KQ~NHNnHWGeFNCaNxPs-O)J{tK2O>3&Sq*(Ynz z&V?t#Le9iIGJ-oi3vX{tF>5$BE)i^oH))KAc&v$+@X$*gsUSJDe6yQlPXLEvQN@(d zxZ$Wyy4xvDWqK>!3%F?xTu8llaH}ImmX-)(B13;~t=$f19!ojPoen7-k)DY*ohw5A z{`PPQg2`|P9uY4~*BzXh+9UDFN~_-}LVy`C=*`UwzyMeAs{Ek<;3hycMS$WE+s~=? zHQ~Zr&vZA!?oAAYl06Eh5`p_EqrlGx;)h{j={W%hB&%#W+gIY}oyq3CISF)fzwkXB zR#>B&{~C`Gk{(4F-#W+E z7P8t*Cd`|!|LyS>;*zk~gM|m;z>#3(zci=Wew%QLG|w`(na?|TWO6R91SD~Ip$ig3 z<{3VLLXIi6Qz31SZ}S7i-5&?@6(pWl4$hYk6n-Vlc6|zkRl^!Hu2mJc|c*w<3=YigffceqUIuPEnK-UKaOj;!q6 z+N|soNGcy;1a}WGUb%R83@45cVFZWbX;WLdFGKFpK-}X(j~%%SvulgK8W#>@`)g06 zd1yBVx=4oV|76n0eRiLWWCL+&Ih3q%o6B&?m~m6Ra0gr$-CA2(0USmx^#ITZjH4iJ zHYNi9w1JK#TcmNSadOW5a!UhZ{A*q^|9cnjsu~_{(mm+TuPvkOrB(eq6C(zC+Fl!N zS$}j*1rzh|%GYNIY)BQyt9UE7D6_QUxw6qGjHS(&*ej=fz0wsj|3TLKmx=wgTCXi> z-*J3+vFgpsi9m+{*2SWs>@nlLO zbrGp8P&Y0fihI}YQrz0lv$aIHbTBy2&I39{7`IH?u=y9ba#S1$u+jINt=>5v*^hn<8 zt$9)Wxl4liY+6zuGHI~wk3AjgYDf>p;YYbcM^JTtjuP}cmlw35vA8h})%Ix15xc<0 zTm)|f?@m1ky80OndxcYdT0=7bH{3g}9bR`QgOD6!7K>ULneZhM1e(R?FAkYBvnJ|&Fl7dg)O1#pu3LlIK-UKK2cH}Ss;HP(sph= zq3Y5QiUq;|p*igjD5hI30<&$rzI49xOUR59Gv%iH{YelR4uy`DABnhat%X*uZN^VL zDyhf|cum?r5^jD{y5al1;s!;DF&6@@$_@Ebw@tm8X~}6!zj*uZ;cO0kItO~otj=aN zoZoBwu%6a3Pmo5q<#8Irz2@Nz8j-6nab4R=~M`vU( z?)$o$)x=d&;;1wF62pFny)a=Zf79u*jocS-Y;@@;Gs38m=atjtn$rJ663B!m0S;*r zCTl9+ohlf&?T{I_yKoyH{x|q8f`ZfoEp1YnhN9Zp=HW(BRB=5z0fl8!c-g$gOH;b+ zk#6Fuu$6v=a2fRylm#jrZp=|iaUkqo-*X|=CoITSoW-Yeo1d1e*ZZ~Wz!9nV_M1rN zxVcCS)L=WgDFUZI*q9~nif`3L%hA8)nHD^5d(E7xV*9l*V9On%1&+`Z5leJ+!~Pbo6F^d)pLI{sGFU^wDwAX<6K z+Co#YQWpl6BgyC%`s$(Jb@Xj}a9oEudiCC-u%{@Dmt|6aQP!aC$P=^5eM zsIX(4_S0rvp20SEv~xSoUJ;kMWY3fELaIf6$5jxcAPxDMMlIx~ZQF&%%=LV!GK>EK z*N_NfwzS0=;ci!$;!U6&`$PZN`86IUF7^K4aJ^*tp>H;q>@SYpE1d9C<(4n-c-v2x za;HuJ(kZqFtwrM=0rtdOrCm;&BTjWT_a-tWB*^%l!p|$q2a@BlkFL?)KO2pwc^-{T z0AQ6{IIFOp0^HhHxqved2~B zV{tItDOOfaU8SukUnbJf@eRp0dz2FtqL$W~0BVKRo;{NmfB`2+91yW(Ks*ZDC7>xy z8>t>H*rXiT_-J(|JfLRds_(_N`jA!%lWp^(us9!CD<cdSc7!o=iOJ5@`|zBy(Z*e0d=FL&c%D>Oefx9z`9+R;dsNxpCf z&)^?LF5bVr?A0F!`lkm2{{?dWzu_l%xXO6Up%vtNg}QvmdS`}O{bCO${e?O<#k&{Vl7&8-k+W+OOi)xRvWEls~|2F*4z$OK^f@g7YEqG_`KrNcx2oOgs%eaead ziAr>y@32V8QyHOEm@#%kP(D?PE3b}P_QmF>Sf9qivLXyn3Hp zv)B>n&{e|4WsI;2g~huKgY3A-N(W}|9@B&=@6q&OL~F};iG=9SLBVgP)?#aSd0X7w zxP_5akC$v_5-D7@>V73rR%G0VJyxw)PIaReqndKJIl*s+6eWa8{fWn4@=vR=#iFa6 z$zl0ibJAmeux9QI*;0BLC7}c1yM^!Beq`V1No&3rxO#Okk-`Pq-V@ky&$Jj;b~ckFWD+0#s;bq_I5;ZdtvmP* z7%Pc;q!9tUnPgnu?Fh`!`YBr1;p>C%8SzQ)Hn!LaV}h*GUKbvP3|_F~hJ9d9p%p2v z4I1{$#rUyuM^!zAO=@{G@-_uMV=A{^UoI;Zm&7)gEA49fx9X)-j_{@S?OPvhOhL{2 zO|S0Q8E)1HASbqAy8q z9G@J#Gwq(bI1M2ldq<6pm5!HUTlOCxG=EMI*&W$a$M<5@rG;RNx#^Sb z)|YtJZU^Ko!MTU`b#U+$YwcY|{kV@HqXGG@^gE`RP{{MH%2)d#tOf}Yz4l5N;)_#eOryiX%VnuZb zZ24k2pW+TU@&BDA@ozxmOx=CEPL*uX2{@Q2F=no)m3CH{ z*dGM#M|xmpL7O=C_2=}|X5fjK>MI#s=muLBCRDO@%5@jhn`F`O z(>e+~eJrXO>_M_$0hmD^!cm@^`P?j3yVvR9*h=DI__M~9J?nmCek0i2r!lEaZ!?XI zVCAr*>V19>OJs+WPSPTlPKx`*S5Y-XiS1WXm3Ez+v>qQ!+8>PMr>;V{!#qnA#1|6J z|1i-CL`-U?bs!a?JuaA=;$`f91Z4%3CHHh}>2-(FRh+2LT!q?NcWl_?2L_DP7XSs3 zhvG(sydMjNMTBcwukA3>#gcDJlLQRIeKs=3+6mXCvQSG2DiQ&9PR6&>p4GM91HBc% zEfvp#(n^LB{4$R4fAG|1YpB_xY7d3tiv!Ws4K(8osrR&(&A!T?$j`<6iZ>S7 z{-|ZS*iagB)1;BBKgEstEni;b<(xlWOMW@P671e<9`>NfjZ~*+Bz98$m&b_m38PMF zW>}%_RM#Hj5^YE$T6YHYph^0~P&-LWQ*RtM!){U26BU)7{ZQZATPDV#{EdlJk|yX& z5R_gHc0j8FXneu`#`ZK=K3#y~!2JF;;+w#N1^o5*zFNnB)jMJeHQV7G7Pl7(&S<3u z{vXkhCV3qPh>zx~1!LS43;K%5VHX*kpCL%U&4v9X*Lt|VW!q29hZRfAPue?V)Yac+ zbRPC(S6##u4c%dZ4J`;D@JjvS8uJ0%6+T64Zf|~TO~U)hjuF1UFWKkSHFfQ#E~Uc| zx69@&A?!lwvPo&iDA*xf!s6vqVj28<#@s0t_N?(bKGEUmoUegksf<8F1V z4?jrfyV2m@0ln$DWUBURfl*HpKPEr)t+2Zr?zAUf@n%okmr_lQGeZNU``03O@%{p(_6OKzd@4GT$^ts)N>@xq= zmEC_q^JjfFAPViLmmjUiCBTz<-#9Pqu-`RzRpabO`q`^E-l8IunrU(tZxmp+B<{Wx z08WZOxAL2vh52XAiw*Gy6jJjcZy6kATjD9+IY$kd*6Mn-rm1L+VNL`6QNu0BpMeXE z_ybz!x`VgJ&nGT2_&)h{I}2Q&xaxLn+DlgjmxLEish3v!z!@zXCr!}LT0?vwgf-#&i$E|8-tY%smD8h*r(y5y-^{k zcg;h`EER=UT^1J<0d{quh?>W{TWX8vjyObH5A}NG=MGx&CG_*j@jahM2V%SOfgy#U zn&7t5@yw<_#8~a*J#L!||BEHkc|#h2I_lp0-wRvse;KtVH6zJi`{ex$#dWc9M=+9z zF03%|SOzf~Bm@oF+>O+~1@w8@0{(83ARW@pCP!avShc#IOlX1+n2`fI$HCU-)wvUc z_P|p*vbw`aEyFjLS-mwdbnKHVu#E}|Fs<;tI#qZBJlsIwIru%a)_Oym{Z^3Dmh`g z9)@`o<}Y+FSomM*t=GB70T$Xb^#P~pJzwF5LhP|DZNTO5--$o0 z>ln^72822jY^4m9`EnAGH1@~OVaHm!pp#)Nyb|&+V}MpNtui@P>B>P>g5oAARsFZ) z#R7ootLGnr8g#6d^Oqr(R=nM5M(WbfN$%eEcL)a`wV%;_)f_%kw)%6?~=DVg%;=ZDcvX1TtTNc~AIiLc(l&FEO z%0xk;NEmK7o{X6Y$6uftBO_*n(5-w(M1>u>Lkr-7Mh;Vhz9EY^7LgkvZIbC}ye&gl ziHNq4{KJRSkR|0=Y_oSmzjI<-KvWp;RRzgU>og5Gzc?pBh-o!wchQ+~h`~6ubKy~7 zJKR&%lKLp4nh^n0b{7qi0sL(9P%aZwq*uUo%N=HXRC$2L#W3c*=)+|*HhSdG!`&ve zxWid1F@+5#a&015fa>8CubZ$?7m}qrqdVm}(Qj@N8br#wJ_**(`hX~j8zg)WieSa1IH^Ju?%Vy3TlpmY^ zGJ&ODbS%U{L~1g4UcT^Y%B`fC$c(8?weg~Jm3A877Jq4krebtIH6ZuFa2>=q9f_+_ zn4N;urk2xsWznQ!0bF?IoU<3h)IO{tl!Qdq!bLSHCQ+{2?Q=DIX&Mz_t}GQ82ISTr zC=qr>#$@#?ys9qh#o@P6qMUOV97pbt`%o0E#ix-PXkeuFUBUels1J9A?msxw}8x1`js3K#bMq6 z?rXX!xjy(I`RP#<#s8JAg0v`mdh5016W+S+y=7BA=Sw;|Ama}CXUWA-15&@K=QE*!>nL&IB51BeNAUgaDq><=*to2vb8t`Zl|)u@WAI389SIBJ zr_1Ct0qWk?=T+sf9U=1rlDxC4w>0+QQ7v^x;soMarsKx{GO1@^z{QZJpJp-bFQH~% z4fZx#eU<{IqhCwK9qcu)<(o5y?n|kR{4-vobcW0fee6I+7#Se8ZS2o@w=pWKEmsnz z9b8(9YUW#P33d;r49AKpr(aKf$o2L& znl?{P0XSb4hIKX{FU-nWS(_jr&Mf|nxAtDc7UJth>H2*Jm4gyP}nkG7?U%72~-n$!Ry?7Ck zH_{P)@uj&Dzl!tT_w|8>iFrgNS_Q+|nVw)eI-f~+zI<*+uKbk_t54>!FMhq#)bAAB zQEd~}QOm3X(e;uJaYmUCW~~wGmqr!yWXMYJA5G(~X<$a0B07 z0oC=Urj&5X5U`@fl@J1GjCMojfCTizd@nJ zr2*vQotJ;zM11x@n`7><7?;1C%d51_!PgOS?ByS28V_Kx5uO#qk16@`?6A8eo|Ng% zk^D)|Yg70?QMZ#h*xz5HM>s8tL5$Ouo3smQk2U@;qPRi{JLT<+!BzqC*2b2r<;J|^ z`nUa>FteH?NC{<{G~5jHJH7!GOc3Nu*#1Ba@udXOpJUSGP-^5bBuvUyN4_y_C=&or zbc1WB4=>L@?C0lSgXNY8x9>VX%f1h+lQV0=92OQMjN|U^&FcA8_~5v8Cb0I_5#Ib+ zF-mkK``Ce-z8qDiD!}c0UjEOdzf0{p=gKB#Ji)u#?bP*}Nr9&|O7nk0l5L-AP8)P? zf3%C9^Bhm7>?V`eOD|0eMoc z`wah2Bw3iZUCN!JElrb1)Jo#pUz^DNiX2E07Aa;iQ9@2ScLW}VRz7Y3S(Btb5r5`< zZHGWzxsbvvG^X&v<2ATT-jLSo&80Ms!*uFb>>5HaF(HbNjC>U;y5GC1rslPNb_la_ zPuc!mok~{2=mWYthgMyBtA%Xiu)k^Xjs75Aai}kkt8{cQcZ}Nsjd+q0m1Ll&JKEKW zL1YNbMKiao%SECTeIl+kA8<-T|CWnTP0Ux_(O-yn_TaBIL};BdU&<+nSFfkKBy^Z2 zsQF+`Q(={~$O}#?XLCXAm4*vQ%RYw7LSFlO6!(C&;+=6SMCuI>{7Kk7lBYf5=rY#9lJ8JvndI6%-A?1NhuRm zOJ-&vMRuD^w$XKd;l*6^Sd=YErvV)CNp~Z7pe%19Z`}TrIVv3ISShCr=asN04GYFu zvJ&K|AmvPlsb1(0nQMN-(oA;sK|eOt#P#9=s|862Nw}Oy!dVCf7IzHxjJPZ$N!l0YqiD<+FoyC&Vk!oWg_YK#c~}FgQ^Z$o7@-k08d{V=mm|Gjy-D2s7aEFqI2;+1MO=sL#xT>@SHrzX zIIh?k2IrTtr{A(XiswRi^&@m!g`D=4_45Ra zEuw-hz+oj8jP8pJbJdCNZZ-H?dRGP)SC%q;7= z0#Pwf8mHZ7y!+lEkru*ezO0&+uD?D`ZGK3xE1BF?DoY35UC-o_P%Dn*nPekU>HfSu z%>{2rRZ(Y|MB0lcNqNl+>w!Ee#gX!}d`8xliJ}Ep)@eH($;HG*YCV=KQOLLIG~%z- z>$-FtLi=67@^Iz+nZhM07PE{ia<7yL(&Kvnk$b1zkEr?_B+3Nz z9+eRI>+0=T;-J%ZX+&GKWB<&@pdXOKOD;$;Ts%ovk-VE=@}{JYjbL)`?chaijL3y4W;FCsNAk?>Byx%%La{DMg+;36CFvm|vC^;Cz(z2dxkWjAF z*H6GhWo6piyGTpp=SUSMIX_MHPLSA}s?K)f5DZ1Om}$dc^PV}<#yHc~PJg-byUYS+ z&s0}IIN@#vG^3tsJWMc`Z;)Pdnl8;2Uf+x3Yap?sVm=2ASC*+4Es=IxP&$?78kZkvuJAev#`;+poRMD( zZC%;@z`jq9P=lnv@qG6FNp{l|V&0baqHkp$#$y*TfD=_gKI^J~#$CK&|Ar-s`!Y= ziWj!?)XO@N&BP978|lP8;;Ql!F1Avb&(*k(g6iKo$WzC#TADEi^l@;_OTLkI_nAki zO6PmA`phR*A~{+cHIo%qULN^2EOj)jvfaf=WP5@5ZVA~df8wLn zujRZ%;F4?(OksbIjc5um%Q~sXYGEmIp0Z94q6!Q*U3{q%Gfk0y{`hcJ%A4iHAgu$h z(kjKiOfZGRoeG(2Ot+W>>8(`#OQ)|B83$>DXCvo!hg)|=XUy81I+#NJ@K7WAk0fg# zLG*c&amPcph3BNCERA)_Eya|Moh|q&@CzBsP5DttO+@(T{h}3m$sg1N-=U8X-|A!0 ziS^%J!!5osw9rWTKR;V0E!c^esf>Br)}TLJM$fWdaHSQONc#(>Md9j=N@P!6m-iqz z^MZ&sX%s;rhhDz{7R#%UF@UE^4ilpbt8Q;1QuZU~5!uPcO6i1SmPNJRGYqkY9RsCn84oouBp z84~k3IFa6i!mBhTq4s^@8?T}=$n#vorfCLFC5sG*$IP8?+O|ke8(=xtfp?&9SXT-fyw0aMT7dXUjFY+ zr~m(i=mlgrf7EVCBBX3VjkD6h10I{5#>5=c`4XpdT0##skdu~3td`7(jHYTnHvnVp zclz`a{9d3&f0t?0OO3qDF61MZtdnYQMqh)Z^RAzls!933c1G%gV`g1_WSa2qVDOSu zLTj!xK?Dnyu%g_t!NyRk-KC?-#-?HVr}!Oz?W>EK=fz1cH5{I>zaKbm=Hr;^TH=kJyJx>jHA49c73E5BgPuLkM8 zD07vr#^6G`Ry#vt8!CZ-pUMPW3>|OFG9@RAaS6tU6&}lQJIjo%UvG+Dj9MN zP<;R3KzXo$J47(KsG=*q*1#7vZty+NNdXKD-*`?zp2s{hCQDkpU3B(FL0yVVCB@?# z6<+hmO7))W3{efApetLB;EL4axr*p!UG@p?(N2?*%CHao+Ct&`da3i6HD^B}kFxbd zm6ys9kH;zjTH-~ ze)7!8g)PwySFP0@J5UV(4Ph8Xn4)F^OHQ>qc*bW8g?Ct@$i{IWJhC>)ykN=UqK|Ii;v z+Xk<%mF^Epz zH-$>g-L^K%V2PGDc{GHC0Ek|Sq@Vn3t&5U1#9J3(bN=4`y6!bQnXd;H3y1?HVeA?% zI-%JfF+cQJiP$+fdQgxY=$4IZ5PEvtTkHwzSBxl3lkUqIYn4(@wnABxy#U^Kis^Hw zf1>asra!#F&qxDLlV`aNp9?)&M@orGLE`hxkv0@NiIq_8!%fUA!|QI^uD$`)*(+2H zw6XtfcZ_vq=d#O?mF8LC$o4a;xXvrxq}Q@0lWUNrM*-89OZjT3Kjn^O>(mHeasMjq zb}b;@ZK2k? z(G`yOAy+sF>V1GYxnp<`_p2F?U_;*L-4Z{5MDsKY$!r0|5KpYr` zE1M))o=dpqft5qo>xeEPGLoDb)@Ym-{Aot*qUJFh13{JBYS!$NR)4}T$L((~mf>{h z_x5bOdK^$}H`<-m7C$0Vs@p!IQQj%w6cML=Oi`av3`Ci$_>xFJsp66*g6c?Re1N}{ zrSgxc89PawMK87MjX|bW2NNSgQI3P^(ph=KG{J7RK%h=5U(2btPFy`Z0OP0+kQ<1# z+s*!W4y!m26F?fX*f6gOXv0GLf4ckbfTptNUqG55f-Z_HO&1Xn0SiTHP;4wxr1zjK zA_76Agqi?~tc8xCRB&diz5oO9;Pyg+-N-lD@Gkfm?kU)8(E&GQNb% zDKp`VLpzB2m*f!VORfz=ZG#NVYk(O;u_YOj9`wRH$i^?I#_)@Xl-|Jltr`!5`A7AJ zT~4RGo0H?WVnPRR&pTb1$O*kJ^c&O&MK-hENq%dWy&exDO7SsvBVAe&^j)384Wh?A z@eLY*&`4q89us>}Czng@>3U+A*&}E^>{*X|{K-Mt_bynBMQE#W6|j+*-3(;~ex`Hz67An_E%l*t2P497u$FE7a9K6&uZr}%s_)nqaePK6 zhBoy~FIH9)hC=V8Mx@PkKkgAVJV%^0nt(65Ax#^-_@b*;ojT$Q>|0Pz40NpKq#$OX zy0XIY%RPZr134^g-bcx$v!wH#e>48@Cg<}berY2ZmNl2{q)o=Wkf7hL{_&Lt5 z?1O;ko;?<{$x)H*DC{2hzRNEWR)W8}7^9uTM2hW65UFdr2afdA9#ok{XGYuEx;aTX z7Vwvyy--x!d$I(YZkMjR=5#FRkG+0Wud7-q3QvM-W8d4E;q=WsNGH~SsNI||Y{2J_ zm;ALUDBmqW{Cw{2>3+xF&%Z63nVyMy7{U#+vA@u0z8sR=i49A(Sy3tWNEsn@^q;hV z^DBIK(_Ir1C!o249c_E*jX5wOh8Yk!S3YSBbvi3j95H<2)If2^FAdt8MPGq#YmfXAlv-7=eSdieZ6+{X`dbKO;1ZUy?7 z;LPDW-P;#b;dHU#@*2MNa#+K`H+hnNHvQ?$qCSBR-N@kr;c^IKFVPU<=_fk2w>u39 zY*Oo|ANQPSsvJ8Gf2!=SD=;Qm%p1P7yB<9&Nt(N-*!6b&2>M0<$uJO-ZzgUw(d5y0 z=pggu4JC;E&}x5|XH_(jI{Mg9%V{;$GPI~56%>4o`~{}Es=0adW7E-1vHKN*Fv@kI zykzN84PUT!`(2SM623*&x>YbZuT~15`??lLr&P4(bpBUV*|kHPhk}xGav|c0XBSVo zk9Y&oLtdjDDIu-mqIV2TYQRsMaziZ$s0!Tb48&pAQ?-`CedLw8&np9>(k>k{&*REz z;ZOJ;WL-V)S+&mui6Hr}$rUT_o%Tp*x~i^jVnA5Ra4%gAo^+y&G|A+6qi5y6Ey zog;aXgdPt8~Fu++0x^rjMHrplhlDAmF0?Dhy} zS4%m?J-8y?+2}Qd9#sR*;0tN?*iY|W(q7$_I#<%8c=B5(U+~dfuWzwDd-l;?E#PzW z2Je#O2C|ewAHhM7!oMJB%;qy>g@%#c!l}^E>x0Vfy9zswZfF~J$Ja;1{S-Fz%PU`C zXe4-8M;g1mn$e1h1hNVpc%H`2;v~nbCftq@dJUAgop@w66+i1e;PJVS4~O5A#S%!o zEf?JH{Ecg<>4lK`T}Z$=_;|@Bh0(+5WtRHt%#4F#{0WC^3WSv>-m~e2zIpg%=Vuw-AO^Y*CC1+WS!b_9RQ)wz4ht#Ko zS8k7Of2W>h6h!p_;DEywS12t>ZIuN>eek(v5X?}```&OHl++=gX0W*6uzD7ib&VQa zI(qp{%V)V%2<{<72I6lH`0qA|SIx$8re+DL2gQQOI?l|yMN+AapR+&S7z+)sm8o8^@dV8pV(?eiOuBm{7cKBML^c_ z6v1Igika-FVS;Ia_wc17w+?68_}?vxoqB2V_43=|;)f=i?_z&>+Bs734VzlA-=Xdy zvvAAsJuM*V*l4FArKZ_=$algl9XED=*yU4{quX%vmo+Bj!bP_?zFr9-xCp9`f^wkb zLhyt1kRmI5PQT9uo8#XezH|Jvu74xm*!PI?un8)0?#hw%V;DvK7nM#-@YJ^i1;Wq# z3o4g8t^<&NC4TWaszSzgCG%s z5cQ+u4plxf2w{k&Y49(}QX&f#5XzaU#r^v=IHKfJlUPis>*}=@D_P(Sn)p*PDQci) z^1$>T=O3P}cds{G3VjdK^eqfnhP^kXsq2<3qy)U@?2v z19VYP+vhMD(bEkZ!or`1&iLW5IeDjMn?uz(?SHfsYJLeFhkoD9E{fH=RDB|o|Ax6x z>b-UYNYaC(YQ4Kd&H<9TD;GK><_&^&3bgp> z4m#;zHW^b_#dkyQ8KcK37JJw6$T$4;DJfSiadGKNwLzc!Rd(sxM(XjBW>RLK;FYWM zE#}zhb+S;K z{XEq9bGNxx`J`6V-Y)|DU+WI{3jmP-!?#24SiU=jvmjSh*ZI>;I&Pxwl`Y+${#S-V@=H z(IRitZxt$HC2J<)xf<|3P}Z>8q==LG5_HY87>#j0_`+>kQs$KQ$5(kW(44Zy7ti{D z;sBn?Bfq_dSCy_bdr=%gU@}~Oq04d@O)f@Y*+7b?ppxllPS`M!^abmf@#OU-Iu48IMxK`4IrQ4zCBsbgZc$YJE#0&Z#RT@|S@>ei| z)<(R;raCyrwjq~~+(h#wKteccr=TStAZZUxVAT>XH*UO;>+eP{@CZuKi56b&2<_ZKe}`*BUfpd zD!^E~<~e&oDY-95sfJK}#<$vBAE$&7yo07SS_+DlJr|q}>{PQJ zj&sgty2a_&7Lf;?A;50>yQb5+=}kAqh1yFFhT2%G7L`7>lb*ja^&;!|v~>q!A*uS< zB?Z}xiqu~$mx~)Ny3mZ}wTIDw%H@BYONp2{8~lFpI#5O2RlJ0KPNb55Doy{jRS7MBpQCHuGhR0VYoyjp1vwi@Izy2&_zQ zOP*AAxx-eGa@soV9wriZ$0t^k4|V|aA!1)#pql7)*I{_doW`g;vi7Tl;9B+3wb0!` zeopfYpsvkKPz`xM4IC2yMmhT z&V_@>7X#kM$cpAQG;D?b{9ww|eeqO*_@)W?Tw{F#%hl3(*BghB3jbEv@LmpZtnNp6 zifZ1E7%tNyALl6^DYtNRQ#tk=v2ZlBKzayI9}tj`I9(IgW$#Rk*o!sHNy{=wf6#EE z+elpCYHwZhz?aF&2$un$`gS{)711|CNlmb_hyqmR*`W)n*eiL3mxnLPFF$P6|9Z>% zxeVW~xC+iK1$<7TMES^Cq?)n!z~EWNvf!!gyFfVtOqZG8bYvD0GH0hu&5S_bypq&D zTwZ+d)!hqI0HI8`4V1_@qiS>1Z2HZ@sJ3~JaKYD`ikfTQwIT8C-QI%57HgS%e%92| zZg+2zN7}TO@PE6+x5S4T)1N-SCa4+j4P|5%j^!1a3YI#Y|E$%!)}|4q0KMEudzT~o z&E~iFQ%%AF>Z1wGcDxhNjUiyx`ondPmA3pbeFfq~OUr4afi2?};TP^~1*4w1_fYYB z^o4vk=kwZZZDiJhkx9T4E#;A5>srjO;DYGePzC*37h~9msKj9lq|5EILu+ z3h;mX`#2IJZ>;9G+vukQx*zy=ba`hP?(dI~^vwI{nUAe~IYYPIkm37cpFcnFKMdYZNyUOdQh?)n5GTx6aj5_lvSyeY`o_gQ`1u9Tx)y}<2P%dL1XUFFBE#j zXr)KD6>q}|6o7-xs=(q|6jY%HqSqYEw1KVk!d85&Mv29b8l5|C>jb?z#z(GDFB_s%W@R(yX5Rb@ZZCZRA!P`Vp@$|Or!0ktYp6BHRYU}DcW9U=8D0Vh4 zosQyh*lUu!(*_0x(Tr@k9%|DSwVAoeNkXmbZcmGV!dD399@KQN0d@wQYPIddTPa*m zh9V!(TPZQ@aS+Rg@hEUx7{(>Sx!>-C)_($Z;P6{IZCnzn0KA<5o|bK!kqu|z2@H7Pn z2Zw?%cQ`4KqyD2u;am()55%ei4Foh!^?LQ$J#antiM%eDrU36@t zKBu9|u)g@o$w4>==tQpp&Jc>BOY7;mQgHn^ZOntS>`2sPz0)*kn54%L=nEAU)Ss*j z*HtDOGhTuEnyw$uU{kYEhP-x3wn-ZeZ9r>;ks1}EcuI>g)_Z?2;C0URkpb z%&G?)z}5f7#E%iCYfpjEKd3&54`ek2vVMwzoIdoKwE3oD*$O$dBR$|fWe?L(o7I5} zUW%+kk|6eJK1KGlNORcggl!hf559_cTVLOe;4u-q?yb*W-qBja)%)0`%pDQJXLa!Y z9J8JU5%`)&IVlIeCduu?VL{$P&Gre<5Z|dh$Ut*#kL6LLveC$;e zr?K$e|NYpT;5u0;CbrrLLi)jrdq6xI2s7ZZ_0EeFMRFzd=Mvbr(S;z)A1TKDlH6%YYL9MP z8kkuEp2hGOAj$TvEge5Uzv9f~n6Q|b7%q%OEVnHy_;P<2jf-Qywq0gE1DJE|qYVzJmC;B-p(fGb|0U6!zYMImB- z-;Oz2hw{jTeAD;vbxp1iVbh(^-ThRCk*3Jlhi5P9(gslM0pwOaA|F8^@K}JzIOeDg zb4Ck-rSGx+#Br^az-pz{uIABf+w)qvA#l*tyTaA`Rvtw0%Y{QtNTLyC##E6hrO4av z<$Vg}m@)r7{>*ktwL>a&baeQ(pCGoMcp=~mjxc4%8n>CpDg`f4VHhL&TFY2#awBp< z9Z89y%niOg7fqqVD2mP8g#~Z!ESUW?`n#!O4hpCgh)$B#Ef7FMCY#Q{Q5;%d@+B54 z#dWWzkB<+RD{cm#Yyz-54aKALjCXjwj3NNPBmxK?A(oJzFJFpPJ;I@d#Lz-G^8c3q z2_U(DX+PE4*jX6;WOhmN3#4&?7=tGc(Qa~YM812lzN33{>o2U}Ol)sfom}=oYG6R! zYTB)5k*P?CTpO?Ji94u^)P{EMCb%WyU5eRxfSKEZ2iU^k7=3 z5qqt3PhzJRDRMea1kh8OT1WS zGm^oSRysG0M8M(Zh%hp7`?V(XHNy|QX%D{Kh+8nCL}1=}^E%<%lE7#|Op`xQgr_$V zaHBG-LfFIt;CnD;HMzI=JT_j-tXDX;F8gLzRy;v)ml0egT=@P?fSF1#=dSTuoTT9b zVZ6>K0-KBP5;0!mZ<{x76O2V|WOMiLSdcb)D{XV|_Bq&c8SDuHfX?DE692y$N(Owz z@1@IrZHs>4owE4$9e}6-qtHh5$xb*!la~NycZ26u;8Yd^8uCYa|}5I+0ZOYb`Tdm`+25yj|KUF3`e?V>ek!xYrDFp!-RS9i__y(Ujsmq(J^ zDYqgbUXCFbwb>(99BC9)4fPSuqwr$d-0bb6d2~1^5YECibGC3l*xDg`jSNNQDspEO zjUCjvBCu(Za9S>5@CTAHa#1e{jC{gOJ|$WOfGPqvF`kf71%kLSIb39|gDVGCSm%RL zh@y-lVA_NY3qlux6$MXO3hAGM5{7on8+ENyvbX6U9+dve{-VzoU&&+$3;@RhOrBmw zWko+CdO?i_U|s=(#oHoqact%o${2w_5IqptI}R{=h`=6VK;d*~N;T03w&+7GWCg=D z0{#8xEz2^-#>Qx4u+_0e;3h(Jzm89xGnY%@aoMkBT2DYfOtJeN+s>kPtp3Cn=UWQL z3AX+eocCc0(ne`xQB&BTc5ng2!GiKZ6q>On@I>^?#{@QjZ7~r#xiNc zbM}7rdH;a-%Q+v`)pPaLv$|GS-FH=Wbw{cy%c7$aqXGZ`ba^=`bpQZi=k?)7Mtbdu zLS|ZdZTMZKbzC(ZEL=TIoXr6rOnJ9W<({VOqA)%V&t6>*oXO@67>wD1$P>=6QUvgyMZB|_~!-w&z@?FbW{8P3_$Ak3*q1S-=qK4 zEX)31I-rMXGrgbiJn!W)ppVyYig!a1a;12F){R+cO`M&by?!bBa(Q04c3zWOxwNzz zHrKktqr;5v`E+O$SN(Ed-9Ps7I2NFp7Z4w7@*kaqfe?Cz9|uJCc6~>8*KnA^582&0r!Zyj_%-zAh>(0@)#-F`Lb#B_~!ZA=*6wwWfw#AZY$|g7r-m~>{0o#4S{qKMWhnM4_ z)g;h1Aq88m@5O+(ug}7e;Z0py+mSijzkc4YTzFp$(2MRrPtcQ8N0>g3tUZoAo_IhW z%wL|XJle_yhV!m<^RA=FpiAw?O9$Pz8x+qQX})6~0Wgm_*dsLHG0x};rvKaid}D(O zVO{j5|Cz8Px$4ocW#vMD^#UKM!@(Cy(tP>=x*^O%9_IM{pSk}L~jDD9=q5c;oHw%*G0PjAE8ZrkLUbZ0PC`^xeV{EeROUgfxJBE5`r1y>yc0Hgd^6N==fCl#U>e`(n6AL5?(;@|-y$5SH5 zbU7w~f7x~Km!K#AxPX__m#1jb%~##zA@A^P)6>&8xgRh7pVKRBcm#{g`U!UL<^{Ar z`}+DmMv+4QffgJfYXs@#T=cm=O{fp^@{hRyItT*J2_Q#auAjrl zo|eZD0gu05Zq~@>P5+zhkb*ZlyZu~-UsfOw9snuqCl&{qc+L8BEA8;d`2l0Dwf4ZBHrFg2@)qn^1 ztwAp?aKgjGF{e31h?iSDPR(E3y}j?%DEj{!s)T41!Xn#5m#@~n)+4xjjsfT(Sv^DY z9s2D%#N-Vgy9JMR#6A9vTOVpa8Zx{%9TU1ldqs?V524Z3?-2`)07GVciks}zA@irZ zi;IgO!9LmG!?|k6(IJib0s4PF^Xz;>;~;&l)eG0b?@-^#%PaDi-MOUbl_Z6W-(9~q zIN&Po8GH3{hZmX_aF=$j@;o5g>F{#n06kf0xs6%7MSpCAz+h*~E@K=2;Oz|0=p1j} z{V97T~w&${JSFrQ{^jbpcx5;V?W22*IuX^A1JoQ<7b1Lk=7w(U2bU|ly5k(I5 zfxvvuS=KICUb*x(BkwMQ>HW!E)#vWDJHY@@z!~PV_~U@+9sN13=sE7~=;@=f@0^F9 zw%=H1r}&fC?S?V&Cp>o>`N_!p_09y2cyd}mSLnRl-dfC{-_ zg1}REK_1gyaEvZ_j4q?dO-W@RpCB(VIDiq%&B&vdF%LQfc^o>Iec7XUHG}ei>*^}A z62&$9^`G#MiW{%&29P51JHZlV=)bjcJYH-}^V3~({*SBnG(U?H+?2tbpgp6&J<+ilG$i(jY1D|TNgYGzIJya!iH==c@uk2U?C zYY(d+F`LC**USH}sh&p(>_GW8ZQFNj&oo4@HC`vUuR85AdU_RB!x_w9{6N!){@}>7 zoCovD0|9QUU#=nTN4pR0)qZ`7r&pl!|HJan&Z78t80mah=KRQ>y8~`90fCUG-!C89 zuk|6<8t&kKJl*xK(S5Peea-1puhFA4Kt0J1+84tV;B%kk0| zT954HayNn&NDz$(xqNkw1F*;2 zxEIf-*y`tlYX6Bfhm}9QufRbIgd7dEgEbVipWBy?Z@EM-xrhLe^B9M%_EU;^Q(x*P zADDfcipS~dQxW;ne?TRYal5huX{9E*^mxVRE$_?D8UWD#d-bc5HY1x;}Kv?S3S$;)w>oa^DNz>UEU|9H4#IryXRsBvRA= zKkYIY^yL{Dah_sKTvTSFmg2FKqQ~g=O~9*1K@+=Af2o9A|BhGpUKk@MC*L%BISh#T z*P1NA{>3z~fEO5KYc1R5HvHv`Vl%6KKTG6@U*y#yJsnS1g$*G7WPuG@E&nj~li+^^ zkguGY6trgdJXBKjdGV=d?J+9=7jjQr8ms=lnEfAE{J-4g-djx*t!)}-}tv?y?cquiTtljC(zm?GM{jySYAu6f*fgl4MS+zlC- zd1+NM)j{p{V6uVog!F6@PAjE+j$rjfUVae9#b9R;p_oMnwlkES9I2pEn1b+Q zb=;G?U+7Xh4YwiC`LV&3UH+|kKO!5bY^tjJ|4um`01HAgv?b?S8(*n)|Tcd*=`ki=rn=D!4eWDR;v z&$|)e-9tzLgW#H>e5JqWuYWcEhKaVOh$Qe84h!Juw(LTAUMWn)+UxQI?bZ)odLTRP zh`07x(A=p#BPbh=`bik!@1~MZ__D&R2=68{0swa%r(4=7f{`Z68XWs2GjMaySJGzF!5ym2yC7q&?gi)v=U>~s~QX>;$l0Nr~z6eLW`9?w6 z2@lVJ(rs*jYT7|3GtZIvQNl$8kddGt*ATxROlpve=#%J^v;DX*;Yx8e--DxSESo|n z#th4=du%b_O5!9HqPikVzRHa^;3bTB6aJh&ZpfbbS;i&z>Qr;#4bN>SPPQ>4!_p924!mufuWzX}a?X8ISq~vnIF*}^p23L+P*w7fBO#$P8k?uI>G4({CSs1N^X*H4BQnMk@3Q*N{j3OJnMNU`~SmqD?c3)r%vMXIPdYpK5UK4bN;t)^&a&d!gF*Fn$;;Z>eWGpbzhE8)0_~)e zpkX3M;hs8Bmh_3bPhQWh@IMzDNW)u>;Z$n{iWTPdFzG4htuwKG$nn zg%84(SRsSC`r%Dia&MfF7+u^_8Bz$kiwzKf&2&Y-%r<+mS$Fp~lQ%5fJ}h9bUq4dK z0o;bC;KlGkKU&g7qBn0j<9R4Ksz{xgl&$x;S}n#uo0-$_)tELA5Vfl~O3K&^IYZ-9 zGiN;NZHJgKN;vTdfnQ_@f8f9o=sutHngHKfE@K*yUEG5^)|vC(ELFrlUU^`6$ITZu zC%c3QL~SxeLvw~6sO5iCMUT8RM@!m17EH}f4!FZKSdTV>y|q8VIM2ltjyh?Ooad(;sxR!h zEeyDzpk`d6V=b$*OZ6xK>fNA>?_l9Wz(JbEDtU+~!z#^f-iiN}G`HP+1}m=;Xd{Fwz-k<`6Qk&3+uYh#S{IeAg+>WL>8xp~ddH zS*6RxFrz|8LxmqHvVHt%d{)ORjp59B$GG=0&h-Vk3Dcw+mx(R~3&t%Y z7D<=x%BjsA_6@aJks0KPWu#mKO@!dYQgPlhdS%WA0Njo(sEbCas#>e~!M!8o_7odo zrO@smK}>sJmh$(6al~6Pv)pr*w<0vW%DWD!wulD;i2~X~Z44IZ1`1_bvw?=q4)$g% zlAM#1P|KGmUdUcE(Q8By3~(7n4+869r+`Ii0TD=$oGhO+_x_sL!M~J)VcV} z0b<-wS;8GeGaWdx2G7D3D9OFGC_Z<&q&)+U@^#I|bB_ z@C$L{$5apFNy1Nrv`r!7%Q*rFNAg4<@X087*=2-c+__w8=T2QwmE~L}DsIp;wkC}O z5-+Xl7uWHx_ULlS_a6Ln%YP2G@GY~sBWcEmYNx1?gS&8@>EVDigt^ED z^^Z7mSS6fCYGiH%bcM_qfB4pLrcFqNlCaV+YLkq^Nb1d6;o_0Z0h;az0FEk4SRlf8 z(Y^7nG^Kn-Qh}hyZGcLM=lC}q8Z@;F!-50_uWk9SO#qg$NX7_{S zkE-*SK3>Hb2dW4op?tCYSn3Exh~FU?MXA{CK;EB{?RcPzqbXt5HKEPgxz*mBlIrix z3+sz50Cxj27YOK&kJ#h5q~|JvtXg)_GGIg|w^nhyBl0o3jSo_$A^TNyrK}--cQ!Xt zlKh4Ux@Z!x>3D}U;N9{UnIwbBdcd)e&)!LTPt-CRat?YHy$v#Yp@|r)a(uM!YP-Zx zaZo;6UZ8TE?LgTulKkkuxmWFMDd;UU^;*+7PNZn4*kAn^W7 z+Ioc+u!qisZ&FMZK6W*aqXMNHW#bG1WkiN_XIh|0nbgFogRWGZjxu$-sceSwE#3{v zjMJ&CIsKIZf|`@~-sqI8A#rv=dT-oxJ~f@LVtQg7FRAY#mbNqef}(s3MKkAz&BXXD znQsLIG>;a*<3h~?&t{Ki+#gs%R6d}=4o6yLn|X6SbmOo#EALwo`SE;4bHy&#_sm)R z^9gnD-}SdvtTm7&UXPbPMUAVl@XbPe> zZu&Zrjhp(La6|^IGO#zCEzL&stI73D*wo23ZdrXKHQ$WR+But_uP8K}1c8*>^h5}Y z)cLR++u(2@MLkx?oY7V$!;;7)%*>;}A~i8hsbsROKc!s8kE1G5@q;e3AO2uQkk6JuvIXP!&*ELu-- zwK%D$*pNJTAte2qb#`DA4m~UDc1Adv%^47oNj7JU<)0#>kaRVs0u0U(D#UWFXblLtVXr+*8VFp1+%{8(yMi$*Mj%P;+H!*61u+Gz67)q^jL1lm z36=Zh+O!MJmir6w&pV*e&&#mCr?}mxx>9oeLWoXo6v^kC?4*cbCW&!%P87M1oqPFo zYCX<*?r|*Z4``4iN=x*w$!>KMhaNy)`CpI*6Ky`3Jpn6-VzRltXFAYKAS7Le>VV=5x-&x=qc^#qO;)Wll z_-Jc+H}&9EN6i1!^$$21_{sR^9g^$a^fjIBsldDQ8ld}oSWac~SGYa%)LHVQqo%q| zm!ad_RJdSq?POMbw5B?>{s0cPq+XoDwwEJ})o;_@_GdsyF#F8VDZpD(V`wNAkCMe~ zT9T*3U6mFiSeZqvikc>g{$ao+ezGG`Y(RY08KQV*T6NQ>@|Xre?=HvucSL&I7l_5V zxhJk4cSEYPoD?eBc+gP#eUMzP-K-tC-Ne=7b1`b#kvNY*v}qLy0SKO+ep-Sp%hvug zkJ6L`C*uXx3hhk%&sZ;~)Qh7Q9BoNjA9##50sg567lsAipIJ?cdQ24<0!Sk#@1Gh` zdyi!}-c2)FHXR@%*d)ggJ^P9o0v#PQL)E)WRliyi?bJknS+@u~d$yFJY~!<)vcU=_ zs*0OgPt5fCqxS);o){Xq)GL2So^CVS23jl^^q+uVKiEng{$o*soIj!H=OLNm&q9%# zLUOi6i)SND=k&bgJw0Jj{Kpo*LS2W0sBCJWt%KjPxg)cZI&dDPFsN*?-yX~S`3QxT zD}82Pj>vz^imm6bGJ2;Lsf}+(1!=vD?-I3Aj*2w0F&WDsBVz3wB1} zVH6Jg+>T^VdBw|lJ3*fJvRHCXGA0_fa!ePSn?fo5sgN~%ApNrYiqsj4UI0XC`w5Gg z=!z6DHvwj$+9kZV_PsaEo_N-=>77cPFu-9@uxJ-17(o^rV!Od{{3}qs)Pezdx}wRi zOnXQO3dS@K5!U`Bg;BIZ#%VyYO-?{Bfk2qZ$kIv5-_A!3V5I4`jR)hflOsn{{SMiI z&y-KIWdw(H>6OB@Fps*_4-iu(0X{qRbs56Pc5}q*SIMw}Bz)v?#^r=2Ce=tSbYI?u z`+ayjvw$7-hn=-+G^l>E0MGv~ZcD$)B0_N$M0L}TtpT>oKalIw?7`2c3Z3DYbK+xy z=Bs7U=YY)7F;bfgI^~@=izeek5%JuFi9)+DKphW%{5!Bcm2>7O-)5JOx)|^kRRPt^ z?1p2O!_{)YVt`-Hu~M2tmUX!ZbYX{6TaF-57y>V#4(Z{_!Q2l)6;`5Nr3wQU=vArD z%@Xw79Qb(MfZi+Lf@^y@+XvvB$lkq6LPCo-w<|p@vG&~(n_shHuL>QR{0dl9JR3g^ z(c1YHoL!!Z0MJCh|DM-pfU=d$6)q(>A_sf3v&Xq3=l2fxw&Zu_>>a*pRwA?GYEYIm;LzrI+py zQa;AR1JwS8;zCCJh3H#h`8@--%MIPQi`I(_(BgWc)HE*`2q<|F6y_BLpokg583qq8 z3_Z9gIxb~|eSBKo=d*?b+ggFr_M83^9p?yRWxt~~V{J)Jc{-T1)LoA7Z%C&?8pY<>#$%|RXOC!|4`J%i zYyqR3;CVdDKrHvVb34N+txgU|lAbFh=I_rM47s8|!Xu6kYJ2DX(Ke6Z!@z0mdzx?y z`Y#&2e>c=$MkM-K7VHKO#NwLOhdHEfIZP&GLq110#D9$;Av8%F&*R2D*0%1~%^7ME z<5}!7%#N=4`2HRJ0^=tEe<7=o)aT)13k#Ch*PeIKRLvr10U>cZ%gZ0H=L}189}dwo zheB??rkl?`CEo#UQi(c)nx}(z2L{G;ZAsj4mC>kkzpA7z%0)F3FQQ@2#qnr#isT~? z;_WWMHsuw6D1)gW1i?9B$o2^9q;mQTTJ#wuJ|N@4Y@bRy3n#Q-imu6D0j`h4Ifq5f7^n60jTHLA1 z;BAz%K^c@&VhHbt%ZPa0k~I~^rXveZ`@6_SfUTN>r+L^{}s-O}2plyZd z7S<{2`IhW9*!Z^L#*WB7nS>Tiwf!DK4a?VLWEy0|*DQF^BnwuV{ zi6oBl@FPto5}fl&qFYKGJgKmp7C2_d&?1<^ zowjS5(tZ|7bEu4da*TMxBB_QR=Q&PE&aKs>`i-G%)~@WU^Dlvy2GbD;#w!r2>N^<%VzqmXzu z5RlKoh(`9w?RmddR|h7nTcTw&*{>H^z+Y#oX0M>#t}xin{wX`e7|AtZ3&i#R)Y_=p#$!lI}z#WF-h0UJpdeN3q+tl3c zIsJtX!W;t6aC)0)!B4J$o-4h9zM@gHrivSyZN;el;@_vtv9p zVw{wwR2*&tJZe*-9fFbc)rcIMslcH2gF--QP+);A4y$ZWFp@nTGpG7aFbORUvjE&C z_zy>LAyD0FydzeGP1K^OO8WgGwc)pk=dZwCuxnwbqujjkYv?9XpOBdR^E_VqkcLH$ z%u83BPA7733-=cy&D7g*yI;(kwQu@7X?0I)W+ofO)ZMji4w*ZXo$%gGXt@0dm;4E5 zEQV0^FnOTmN<1iHNaX8}e=B5j_!QrfwrBp^)p(v$UkKrAxZ`rIyxB- zs!={%c5?5cFe#uthnj2-sx02(p#g_*Be}n0V|x>y0^$+bdP$57DNdw88g!<#(O!;U zDdSrKB`dWJ+V3>9Hz0cDk|YN1TEdEBYfbM4)jw}SnOG1u2Te8KXJ;$kiNLp%Ax%p6 zIhyJog2HL4PesM%r9y_((7r1#R#xJ4qXXBXB|Pn)w$2zUxk1|d{>?1OivtrWBRBwL zs7a}sUCHPTUVm0pd{WkgIFIRD?ixU#dS+=u=5>CuTIrhfStO;u7|(DHf^Qkj;`W#! zuX^xYGw1BUijk}HG>O!uOi|=A`FsE^%8-lNd8EuOMPk8FnWyApyJ_=lpXB#XvzY-Z ze?N{xf7U1W#!IFinwlG#sfa<>EqIFF5?O!1U-@grrWN^_aVKSALg5!K;Fk(*L!5oB z4Ng_H`)$V1S~Q953t8MfHo7!vC2U^UJMaV}I_kbmBfOPeV0u8|-fEh|l6p(|us-E( zBRTP;ptLs4tEs7Q;pBdSQ4vUeWRG=^3s1flOtW!P-_O^~5)`=Gel(G3XSkw(%k=|0 z+*Jq|mIOYz$9UR@_u9Q8m)m)|R~M=~{-UP%d2^9Q7BuG-5|iw4HAezwLh%HmcQj@h zAh-f-R%%G3cfYsj1EI-fsx})iPdE*Un2(u#hQ&;>`GR!ZY0T9uGswnW6N6m^8FZn%k9RU3Ud7w+FSl`b?rBmKgwb zI(9a0iJ+4kp%Km~6&p#Bbl{qKgF+>lvL2(|-fl+tZ z>vilD25)EKvMtgD8GB1Rv8caN+(dv97wq%U&ji=k_nA9q86NO{!&%c^nOc>JAOBVB z+xl@smqKYbjML;Nj`Fq^NNDf{?=zY)fz2m@ukXBl&@IlswgC?OH(}QAh2_v7L~5?a z3W5EHyLD*~Loo=|1nVD^8eGr|qH{VN4QAc^X7689_WaqP`SQSGQru~H;?ni6%g-rfd`$X@xQd#R@N-RkC6>Bh8Cw4MZE3 z5=9Ad*sjl8=~Zg0Pqu<2*k$iAJg_qc$pbB%Rv2WAM%M95hT&W*FfQYJ7>yL%IX?4o zlO!_N!}9y)Ots;DZzex%dbU!ke>^ZNH5JR~q@j^5u80Fte>277E*$89qwL#MYCuNw z-0c{TXcm}mByXv~Xfo6MF^oQPh@4KxJ}wKa+-B-CYlC!tyzccu0ecD)pwyHWoTp>e zjYkggy_KZ1MG8pe_n>u3qdwbFRiy7qKYSXD0h^2gXPIg04G}yGp30q475rGEq0}(L z`Yi=KQf=kXN(^dhY;mh_-36zUqEPp?@_nVB6lV_Nb&!zzWZTE)nX1GZS&USyyVo?GGVF1#fXkY0Zh!E44z)n5bunsfm z>j^8iGJ@|Ip>{|#FFiLb+bsEa6|p-HR#)cnAdvX;3Az|VN~9q>gLwtJqVAQHLHF$SxY^k2Av`=9hzSS8zMq_iB=FD7^&_D`O z2Hr$F3zV}vsTmG}(5HnjKg0#U0Z|8+8RqH+~3;==`7hJE_xkL>Sa zk`*$vOUkBK1l?F|RW(nI=)1o0FqG});9o31#g4Be;MDf!)Xwq`J+$#@WiGr8gFk4O z%2;QEzEz#!Q8?ID%V9Q&0#wC03dh?s+w`ZXldG35kMrC_C7n#`UU7b4umH~NIu@pu zG>F$tp)pdBaBgZYISw3s^F`~ zr6I6IupUSh^MfjiRl_7*@N{$47WT(?TNi%Cic)MS;p!6bPyQ%3LuqNoYIq~S&f3&l zex*er-NBE15%%EeipvzSz>OKie{aq=<04vP>p1Tz7q2#${oaK8fu0o9nntmy{-ID+ z%EOZr$cWJGln$PdVSvb-_W!NAIG`+5ksp65iRW2T(UvWHg z)ef}~kr|@6l8~L{??f~aaymdi{O-TeRC+c8QBck}^|bqTh3iW!6D~0ucU|!BKxB)! zqt7Fn?<%QW>IG^Qv~7i?Z>VczhLhsMAm(+|}po_%kl{fmd?&@)$2}wur_2?^w=jH1PhG4%ucQWQE{T9is zcPEzZ&&Dn&dS9;gTF&OGU*6fbKFgj@VYVT@e1+lZ1dN+H@zOLpXV;{B%_L!0Bb1M6 z!Y5QFw9e@)2fhU1uW&7rS0et3i(F4937Yx1kBUV=%M*i8*g{~r=>R^-?a#TU5<)m4 zEP-h6HOj_)HugOso*m=tE1ov%$8)?elkmZJx-i66P>3#mpE)G%hskUYca>{OdO|p~ z6ihh()0K<>$J1&IRU?Fh6!!+xG9)MI>x%`j$Nwgv{k}k zjgkkn!Q}S_(m$5vaAVpmuu;4=ILLvwIluwuL#z+j{(^FTPEZa*{VoUDrl$x`T5cekG zHT2^dz9KvlY;i;KE7^orY&cyXs918U;*{Yb@}!odiTrqa{t``l<(GQj-ZZ;uHPuaX zhubBtS5%ROQX9UV)!5x$l>M%=+ebytO^A`Tm|6ooR%o+t8E`u`6wNv`#JvHlBD~M+ zWe$SJVBwL@D&1!jpRZt|2d6#=b;pjboK8RxGep8Ziy|_~i`PNaigtby zh(M5`%{vY4V%2>JY(h(En=z1S8bLOag0p20w5ds>E?kf?W0P=86wcFe4fW#0^sk{; z6;0t5Z{%^u0!Mk{Li9Fww34WJxUCKN7D)J&R+Q!?bx3{6pktM? zLRRAxK49DMXx_hzURNY6vAGJ42+&P8^>>LR*4hlr;<{E{829$?eP;yb#1_uYzgnb*`Dl*tgweZC;dT1{IrqX|y^%7^1Uc&CF44jZE}UM`qJtjf zE4^j=iEUAdP|htPZ2#Ty{OV3ZtvmtNB`~Z#7RQqq&{)DhH_Mq+cP-_Y#o!1`KGc%! z+MX=`T-F4o6?q45N?!EsgR=FuNt}X74ucaHYU$*mg7AkkoY7splCn}PBc20P#F~iT zN^gCNCr1$AU1X!)jKl)^+1kVf6E*&J;0+eF|JW57i;z5c(&1d4AB9`#>T_Qr=xA|Rz^@&j;m>COvO>=y6K$z8`})pVlSY~`XbujQk4X#l0b}jDO#@f zd}g=8k&A9#Wnu=5K~0;qW?nCkf(t$d2CTKqiZb-9AqzN|`HkxshFlTq0v&EbeW7M$ zbXmgYyx$uZCkyOWSyh2ca(E}rlV!VOjaQ~|LyRqO zN>D)jSI?&8JQv6LQ$4=4YQlA%+nvUpR*}m(O0}n_6lM7OuT*3Gs0hh&vuPpkndx08J4tU~VH#u9C9Lk`7*^E+mu`A@$H+mmU z1DR9Jff6i&QkM_qLS^EZzZ$o%|Tjf;}3sHbbmFxdl#BH@~dsG9xR3DqeUj0 zeIVS{k6q0_rhBpd93sQ7ogoU^8eBQ2m(dD1Ld zi4Ns?m270;tQWL$&t1)x5BbPVHZlUEC%=DXY^@h%M0#ii6fCEek^RV>8rIEQk~V+J zC|rC`2aqo{7tvMpQux){u*f_{?NOkiwwN;GW7ub6rk9xHt_MV*8PWzaZy@R+eFlwIS{Rnq{ zi<}iJ&KY-uLv?wwm*KBK7wB3KSJAiZTaT9;94{IM=QUOEkaZ;)8~uI(EK(PpuQQFT(VnRo#WeKia0nK9!7Q{SYhgd+uR?>!cOz7=`w;(6Td zkE?mf3qZ}As5rOYc=ycaAkZr<(0R~2kU(4cG!!lW$X?Z;>_5hLODR?ngpCJW7M7Y9 z%{*Vod+={P-0vS3g>-EG0*5zIs)BluLvpGy;HC2ghnmi9t7cVxU|f){w)LDp$Z!+T zj6z&Pk8N?upRShp6yvBxKJs~HPULwWRSQ<+DHfd8d~EU^fzO(YC^+BzVB&_Gf^qzy z88hR!7)%mwF}JzC51zRU2`&L?WqsPVkg*#h#3WN*gYW4Mxv7$LVg2Hy9$hx=rZr;U z@RjnTV}6yUDqRI^$_mnc_;irC=-jh5I*Kf;LMZG?Y(@ z@>b1_*L7sDviqcO8od*9vbnHL_)~bg3^q+Pyrzz{HJ06A~jg8g?s$SV3&o> zOFTtEcxHZx9CtwR^F3uks>J!VUt(gqpQcTd_U@-_F5Y+SEs<3e*Ux(*+nTp^6>L3d z#GKid*rUT}Ti|m~s^cF5;X6WIry6$AD4r8~RG-N%gsYu zx(UjFlwIa0F%rL)BvyB0$0@vvFbL;DW=6o>OAlo^WR^rNAnH*$;;p}M#+cl@1u0Ws zi``pJK)T;9Oqihde6#q;ix)1aG6PRB(ej`|!L+uG3nw;jt~U|CI;{IP9^B=I0vjCp zd`$IowojC#sGdH+lXi?2x>{lT*eotZG@}y3<0!rT3`}iX#O0H3*0n)#B2w+y-dZ#} z+728AAvi5kX?S$?EE$eylXBEQy=D5#iks{=)P3scN-IEU zV{ufU+=%Dwtb;jjHMS2t;15oZ)mVvtJO8cCFrNASd`k4F7GgTJ7_npg{egi#w>a+= z^$E?I1}8^pthZVu+XC7hIscfW{9x4I^=vAenr3n%W&B2Z!Se5vpf4!ud|qtZ%$=z? zuH(cG_Ch*{zCE2;jd9K)4L0uz4cCH))s1vs(6MMq^4cT~?ihm$GmOf5cjO)8t-Q(A zt^j7sk%Wsv`i9bI-_cO~Qb%;1LIP*%17EKIZC#*SF>Kfib?je;>lpCS; zt67qViqRd5|O4_0hciP^;H&7%4ZPfI7aI z&D)xWQCw1{T*lje+R1_FAzU^?MKEq>xD!2OBgV&f(bgV%n0t%(xR(1U*>pY4!+a_i zuz$ljcdc{phoEH8@4CQ@{t+Aqc(RG^M>P;5#gqb<_Ip0W{=s zvum4NBALpD=Z;8{Vhj+n!PZu;|Bc3L1`fXv zj*ZW0=^}hP8}0s!A#+ir!8_KL z5T=L_y8p>2g+m0n1(rss;31m79`YOtdpHiPd1LIXL1BeAP8Ei#2UH>0=`dX;>7$|6SfyD-w4ByC+p7`Saz9PHRrfCV)Rp z!ow0P!q!a8A)gfVeoa5yACSMd(GOM%waMxnj}T5+rU%fO#%7#<1`E&Pe~6D$N$x|# z9=psuPPd#w;;^sULooj1{vNdrBN2~&ZcHK|AW=jUJ)M8oeRQ|mB1QFJjU{I=oz!vr#_2ZwPiRp zZq@)%XCGg87!|Ws#~8W4zZv?>&>J~rNWA5wGwnv7ACv|Eu?^yHUoxWhX7TPQAoI1`O0Ku9^#D zC&F6V^H%8!wmQw)ae>*63-Zqz1B~PpL(xXf_q*97x=>UNxcc>khEIcuaBgBAnd`F{ zl-h~}gF;LSXWFbZaItTmJY{6(ybeJU@0<#nM{p`^1Cx@_pVwnx&==1~QvbvAwa$Pe z(KpTfr4o)6VIJymQs7eN{AnCL!036(we95iI&lR_xSa1i3wGx)$cx$j7~0bKw3DPTid`VO8NsWjYj#`-GS&|4 zjhcTX*XDGelF%ITtETol=t%Y7ah#OzLRSvmNG7UJJKrazv8=j5L0<20Yb!%*(`9PB zVg91?JA#Rk!%2;E73azfY|CHLl*seb)ij?wa#HKPKN5p7xWgdiwbFo48o_%oub7k7 zN0cU3JdDem>J9uuJWV}q=@!Zp#uy5O zYOFt(Ax@0RLIig|4}64wJR6lACL+!*%&f3Cve*~3bNysjjRpe4vGay0X7ic7`(Vic)S}kg{ejdm(VEt z%f78~Az&v}{G_Z$5%v8v(ab|!yg#%GDYJ1@H(P1H*+4G_JJsVI-5#l`R%JcND)fMM zYn{C+rv{i!IQUF7%bc#77#Y}f(Ricv_L)lj-RZkN`9v=*_&}4i^)Rpnl%14ULpKK0 zN4K##l`Jpbv57%tpdiRBii&IMAz63p4@l)DieBnCGhmutLikh(=<7a2C%0jR12Bo^ z+sde^v>P|Tya8`|Qo5genAPS%$Qc#`6;Fre-zU>{yn4|rBsZ8 z9O6EDVG{Rl43sMmDmDDbKGLVufo2J))XT+>iRBN3aoWF@81hpHx4dQ( zHQ?E;0IC|+Pm?ctDZ`3l)L49y+-lw|*BKM>is5fe5I&0ktgyK}w%+Hao=ciFtb11G z?97rCzCR3^sfQb3Eo{!#OCID(u4rGwjUeliSQ5{b8CgzSKYM#srTmlLc<1Ut#PsQ_ zlmXIf2GR-snUpYL0KPV0y6nd7@``(BF^-jhiT`@!g@}o{)2>>n%%t)V^W%zaS38hy z>!G;uf6?@o4RJMH*Dcz(6QHr+?(Po3T>>=j8r&hcThQRzxJz(%C(t+qcXtcq5_PQRo$bu|iAZr6$Ak08Ys?Y!7hT7#%m25bG`H=vBOmxzaD` z|5S87w%Akx{WG%O-7yx_3SELCwkZ*PewhrD!z%T~%$^qa97?AME?H?AM2!;-kZh9v#d-KSOtaB_0gW0O@dhv%!aqbvG+xx zdDPFZdRcgXNd*Lyr-eBTJq+nTP9m4O?_ki7NO_XD_U#`ItODKzr@P_v`?8&G<`J`jw8 z?{T2DpRMFk;uUZ08B}Z79>5e5Qyrgi4nlCec6*Vb{0HzALpo^aBP1D{vW^#l**wG3 z$VUVI)?W@u-t%b8<)B*$EXfG$xj$(&J6(W})+-I!@$Q?R!+9QA-)3QFv+C(;!4Y%a{{ zqi^v(_5fB<*B5IZV9~F7c?MK`57H5QVbJH__9VX$n0Na7Y>ZjYsD9GiU1scR9gpkT zWpb{|&J}gJ6D)GjN*JA}1Eufi$^s3}5U+m#1`48?%6||G9`~L30(sp*r(f|x@MOiU zYc)>;!Jl-nv=~tXn|{79TCsA!+l)niTc*5(ZMTA5RIy_EHsYgHEP&My5;vI0jGOFR zmLp@XLAvxlVHa`@2>s`>JAZwlpJ4237x$4hnu#*(3zJ0vOjtAVC)SXr#!W^--?;nV z!_&oP;LW^g4GO-0|>4$VV3xVZga|{rj_+g1U z5&HpERPlg0*?hdi6*yAv8X2>bC^6wCySmd{++_d!=9j@#g~2~lp1Vf9AbiC6vs9g7 zte6oc|9&U&KDJk5Vy5+uEUk-!nONq$#o*+nqcOIQ@{H7(z$al~6fqsOC1K|;fOaNP zP1g>L`_YM@*%qu=S!r_9qv7fiGv>qX*u4r-d(^UVkTVP4jCVJZt@Id&VwJGiWtYRG zB}H5iwPw@NL%WG}hUTN2ppW5U;8Q|)| z%jT336WhLR|P5%HqOE^~nf$JwE+ntQJk#D3X;P9?V-q+&>!?Ykx+s6${n*oeG z-sZY1RnJ6+b;n=P?@!q^cW7#_k(qJgn}JxY3EC?}VylNWe9|57=NNU;g8D-24^Hc! z%0=KJGMZLGZ7JMh*>RONkE~p+o@W}5p-;6SE=0y_6X$F+{7Fq+v<50vPwTQ=YRJ88 zb+N5N+E5$L?;NEc%GmD+H~W;NufE{itNn2-Bq;(AonV9X$TVtzuM6{`jmg}(CpEj* z1Fl@;CIm=v6|p0y*!P5`km;2`k%4?I?Lz@7Ei$h&;q`Dj?3y7EbtJ? zEaZR1`jx=hFVlVcbLLSgf zB&}I-GH>hEqxwFIORc&p7JL#%)L&`cN0rMuX1JDfNw<48K?8XROe~1v(tRIoB(168 zsNES5Y-)FUl{e_59jgCk8kc~%t5w1Oo7TfayQ(!_>#PongW=#pN%Oa9O%q;}9q~r5 z#Mi8@0F3lQmeb9c;@oBhSoT3(OGRib%&me9XT^RS<;B;`e5UDeOIiAQ0m2N;$CTcmL(+OHVIpi37QTi(oZ1v)%L6=@u4!s1^q8>S+ZWRUw?L@T?Z&tc zpo+ofG#$Rc4V&Og@I&JwL4_nA$jF$_jX|(^wNL{bH4LpiumeXY;{N zY%$dVqqx88t&F+^P#SMsWWcBZF<)0$LK#)Xt*s!kehE#E{XS@2sXZ~Vap)!&+g3&K z$Yrd|9Q(b%*(II?PlhHyl_NTV4)nkehH4Kn)u4QJTAfg9+d$}Kavj^pn7SB94^B4D z$7j*6oQy>PLm`zu>}n$x8B0BZ;u@T26E(|4F;p8B3Yd?cucb<49}-#Vk6eoNL7cbG zR81b~jpogI5fDBsIhcy&Pf$+=70S+7b&MIIHwoeO`}Uy&;@k|H{VZ%{27IftIJa=aRqJZ!xsuNF4JDzIY(P6+yRGvIO&L)ShB zTV4NMA)mfvx*n~C3!O*wNwqA>-*$3}DmnEG>11)Q(-3}{(^8`9yMR-der zt$^v+%U{NRuQCQpJ8(hDn zQh&Pt86~!3!HLfsk5q^_A3(1>1Wv`*`&K~L&))dg>H(@DwDV;BR^`qF@vu7**{v7B zb_R}(Q`R1#LtWUI$RC4@N#5`5FUP_8@g*uq%&Lb2URxE)!E_^>H>Z!wZSe7%thbpY zTG8CgMJuvo_1XBI;tRcD9Y(NPaT;lf9XpBmDXWLAckXD&YoQb}hX8=LF`tu`YJEjK zenCswX;@Z0Zj$P$!dn9omsw55H%#*9^5J&dfPB8sA8cyBJM{b9e`U;B{-PWhf`zt_ zhLo>MldV_WqsN{NMne{XC>-cJ>Kq4c;PzolR=dX?CQ5trgrnMLe14gxk-d}|r{_?d zq4xnM0XThr=$=FQWSZP;7T#$o2~HgZ|3{}lqM(6NihODqZ~l7xxqiwTVm!}bc^lSd zYnFXI)6}&>D-Ql22r8u~e8bIOKt8Bn42SQKwNy;p1<4UU1wGxm+Ht&mBFbbebt#=kx!f$83MYgbP>$hwVoHL1>JYd_<-Tw*L9v9Yd*Q8m>~` z0`GE-Ts-Kvs9N1J2n+;@41w1NZsRBMApeM>H5CF3uf&h)yT_`Om#jILvK5Zu<^dxTuriNqdLSww+wxr#*iBFu2nvC4 zM6+|@rSAFz=&8wAa@6a+v7Ob-V)B8XgugB;c$k9PY&)NzjjL;O1#cy;b5KuQ;<-;@ z$oP|7U@Y$(^wAPu<`g~3eFqiEJMtIvX#t0*jxlHaK|X4Kr@xR4hXlSaFW4(u;6r_Y zZHp`cqpAI*7=-3e<#-38lI)SSDhnX zqq3*PRp`J=XZpv=rpfU*^CsydByL!24;O)5=mJqJGh*KaE;7(NP|G6I_Z>D&4o9ja=t#lk*30|@vh}PPb=0}xDZI%ZsQ{J2N2}4Km=aBA;BUm*(i*uQ(T<6sH+z@kS=)kd{&Pr43 zZY$hyg>wIrNhf_IniOL(*8(>K^)I$vvu&An{7QO=oMq2E$GguDCC*m^%KLmRiDw3iDO;E}m7Fa&`va77nR`gM- zpr1R&n)Q4X4(W6=nFLP$*^oJ+oO%DGO{~zQ8s>t27Nra|-uYqGUy218G1gW#_$#ur zPh^_V>|(=7O{BZW-sz4QFQf@nla;z@i;r_GvuHqt>iP5=>b9QS(;Vwv%{*otwroru z6{zd4dbeR~Xqm1Oz6?uA0!UY50SHVNqlAXdAUBau-0lecm*=|*p$-zuqXg7YZOPnj z-v|1J0_(6mzG$03VwRXsGP`<|BNfPMNLD!|e22AkD0~afOVikhm8KcIbtwVvwr^$B z4&!7_15)=aO#Dlw6}j=su%vNkNY`aqNPaNu{AZta3lYDMx8|-^e@b;3r(im1wxGlg z>2y0-7KX@*b^dsCEA2h8tSM}K`+>}K;)hJ++(2&=Gs%4V(l_pvA-oGG7V^^ZCG0mB zF+VB-bd0Yu=P^a3j(mT=2b?dhVviOS$3Q}Z3J<%{Z~eqRhDXXuv5K1Ver;o?*0F*I{U`%(OB}nZ9i(l=Py^13o0`- zwmB0xGTHrFdBnDDoj@G`DkNu6snnZO|5^k9TL~cM5v>=OC;o)F1RCL_<_XT=AU%WX+4K%S>!4!t&Bul$k zU0a?GPzVw4#aKa=+zXj!&)m^LJQl4e&0P%i_}A@)=AeIZ@@gzghCN0$qtqQkjrnrR z3R^IHCts~-%}AgMX|i&VTjZ3=vvnMh4#=5OLSj3|ukcSMy^p@Mj4LV)E@_$wrj=+yihDi8sjQi>TQ5!GCAG#(ET#wcmTNMw= zj2);Mv2s^|RSJ(G?c4}@CA~7t^OVu!Nfluk-?`b)&C@|@f-o6?)g?|xOZmx#J*hD@ z-H4$Axj6Ua5#Z0g5@F>|YsH#LNCh*GF|0=!#+1q-Ix-gbkk^vkkgvmT%QVhj4{DAU zPWjSMwM5JtKhad*VhP$EGl|O0(W%$cLy)B()aVy$Jg_lM+6xPMQ%PCGVflHTu@OHs z4>>Mo+9!=!+4ihpOzHtW7;Ea}j4oJiQd}A=jt4kpI2fZGU#J5ErV|0;Fn*2F1yHE- zdt=D79PNsMF|t!r68oVVv5N`2SDUCLwk0~*A^7$eqE#y4S^w4#cVC}y?)jQ3x}9Ug zJ{y|v@2Co@m4B-;zQ`xuuEdaKz@fv;6*hHb>M5r-i*yAB4H+J4CmJ_r)#ut~gkQvE z6r9p5P1++#X{^j>(y0mHJhkUyNzxzo??j;lUs|OE(4JPt6mF2Yk`g3v(0RAYTC;xr z3a`9~ted>=2d0Xxq@%FWAK8JEAO2$_mm1yp3*C`Dr>LqPwX|UGth@n8QyozWV>wT% ztVIha_Nk2#{v~XPojCGc@u8S`-2C5EH5_2#t!5@2c;43O>CJ0{;aVf!wc09e@?b%u@YQYn~)463LO|0hzFg(G;7ZRWIFj`)18A(4FrGpxbz zpe*H+sVzx467-SPIH{q6|IGrw{r{x`ePgx}3hjW>9r0Z~iU)9s3kc_7DNLs8dt{}C z>y18X0sj8ODhC(`tI~POmTy86qXX!VHDqj}T4EdMk~kHLZRTw!<-0l{`aSw;nL9Ru z*&~5#;X18~PtH<04o{60L4L8bEK4C&Z#p5TEERuuO*%hvzm@7voLzlLwVJuh6vjjN z<{6%)=c+kUp}%jwtE};}kKdwQUVom~k-?K><>OXFLboQxANDB8AEkCIwvf@-13#z_ zl0jPtR(NEXoJA6xfPsKRGKFEQihxFCy;$G0z_7A{on0mzcfT5QtIEMlkqZZv?BZ=R zAW10eMLxJ}ikl``FpOVYYYpQ>$DLq{`y>~N+*`bi4q{(_B|?dfAWcv3CBez`1_nLE z(uNr2T|#^fAP3Nz?z-s7ktBf?n#AeiXkui2ef$8B7)W-Jg@t5C;-oxeu7@6G3ZC5l z&NU}~2%V4(rax^q+tnd;h-*Q-RD0O)Uzz!sSnrK?;ARnkz}((?vGs8|K4Po)YZ4rw zKkc^>BOr@l6w2vl4Y;cpmKo340Gl?`ky(%9+#QvJ^$o8BeZP+1skz{k%zKx4f=}e3|l-|hL>}8*~GsJ%zIS*rU$}?UhNq?J0usD&e z=0u>~$7e{=T8)?*NuD*e!3&g_8f+7Rnbi7PC14ySp3;{CYgWMtPQi+VDjvTepW4H# zZ)`>139KP1M_}EFjl$Z20ICH@^2Y<91BVD#RR?t6qTdZ^1=9fMXH+e_c& znD9-_dWw8tllRm|8i&Zc#MBnJO)jLr-h^!=^wYJ_imf zm{RM+lOUeBy)l#~+BJUAi63QNyrV^?>G}WEKjC^$+)9HTWp7^P@__qBCvaaCtFI z5~6JZbdyK4kOGwLLg$rnp_)Y7&8x$dFSaoZ(7whaw6oS0AA0&$_(lUZIIz?glWN4f z8C&K^tKe9qq2ky`Wxe%X#kswV2#CA!hcix-&0FxnO$r2t<tuY#Y7(C!aaW0n;SX4@|VKbK&p&qb@ zpsBXln!=GW@QC)Y3Jg6|{^3YWLF#d|R7h}1abn0%iv2tF_Q}93{Yj zaZ$MUAEYRt%!ALIC?3CK{d0>}i~c`U)9arGhM70}J=-^)hLzlaA;40?uh#DM4-u*_ zn)RXc-&Iabc2ke#TmwnZFR^E>Db_DeOeepusZ3hX7OZV%kQ`APGQ_MC0txoYaiVn} zr0YR(@jru{Q!;m{GM3ml{(kIvaN7^w3w}AuZ?p+G#M-Xo`K-2P;*QP3G_!Q@r8jrQ z6Mlf74RQc%-zcD86M&=|Y{(2J^afTarlxG^o%**~y6wsGC-mRQ{CDKq*WSQ`3-sqF zv4)cgHVf-Uy0@1N#1@jkl-dMh{n>2=q$Hm-|o9SSKCa8`%S3S`=iUqN9E(YowY zas^vDWo$jx1K^9((#Qu5F?V`FZEK8ME8n@WN}N{#epT>Qa@R%rZ{)1G&1GA+q(eUnriZbs!ZhjKk-Rm*~UyZn`J&JhgLEc9s^F@VPEVvTHn-kYKBF9jc6I31vwbIjRNP#kJfr%GFPCf?Mt&j7DSls#vv4q`=P%=m^ zsjrin2%|Qp>Qg{}3c||Uu)qy>qf4#UoLcLq$h2^T+5SyCYRoy>r#~T@lXI0C`mjAA z18i`6;sR7Digzdcx{r9CfV0|`8~@j;4Nxn`h!VnK0e(F-(S5iF&P( zE9trXlTdY=&xON=Q^bcEIGNCV=PMPP`i+&DUD@+7Mt==JoUPn;F!^`8%(_(Nywh9Z z^*#*7_d>fb-$3$lZUuY*UVa)Tia{HhQg{$p)`;fHWz+D&4o^qT6kVg!mvAfG}x_ zt~Q{}Y?{hM;SE$P{9 z-Ap4-D2)9~y}?zMBWVVaEcBPrJ?1z4xs{Z$`F4l^BP)eg%AOyKE{fAJXEhaMi`GV@ znlmVY1}}FQ$!L$7`*yY-^IgaBlTDVS%8nBl*zE6Ncz>HwlO~-aIgQ{pePgey&m+DB zt6u5Flh;_2v130WATA{v1}sGWSB_)#lR|4(fLDx^+BFwYLE#lfts(U!H4tdIDJSoY z_a$)d?2k9dS^jiAH`(t1c`LUVOqGsJX(C^6$I5z|_@{W4S^|EvV!WBsE9JS5`<7AH z2HRs$@wy|@_LI0A1N!1eX=jwT9_Y>ZgF0Zf_*@uJc>&?Bj9I6k|oCWOwiAaiH5f$lbFmP2sGxWxCO?i}PzPv96c88GH2FC?o_3$M>BC1j1Nv;)m zx?SU!?x?g{UW-Lw!G-G!KNe*E5n)u1gVCaVH#u5f1e!ti>!4EU<1v4#>kQm9+}?_z zBG_IUj=c01u4J0LjG6{~8eu+5%M2}1k3%Jv*vw)SpzBy1tDoLfiDbE3GwJyld@Ait z(?0D@&&}2;@IL^e;Dw{T02At8|4x4bjQfB;edz_I-+|fCh_jE5h%XrZ#!RGljmpJ_%kSc;A;kY^F!E`+?UZl3vMJl55OZgm0TPnd-M}l+dBp#*ef%o<= z%ScLp&Wj+@GbaNm%luFNQfGR9gIJ#({I>oQI&Sh0-fvP=WDBb!Q?azTA=h<75A`J#C20XGj<_de?6Za(nM%Q%Nc%ZjqtjaQ-BKgF z!F7J!5u0Pe$?uJYpzN;2^z^ev21rNJ53lX_DeUcUtlkym3sy%hYM+*Y-oU1z42Vmb zVx9)PLr_QzPFAl??f#rkc;T;J!qC+fo3*NIV;*8Hla{vFq^U9>H_i)f!(_zWc&QG>kVD^n;z)E7nepVmeMWctE++9Y5$OaGjk(&0l#c{QjkU z?s|<=!V|&i(yqei^*!90`VQX^eo=}*xrq?5;|o+Y`Z+(t+CZvHxU#LVD`r8MN#4=)3ti`ir3*roynDc~!3GvU;E|T3yeP7(TQknfoEgugpA7nm#nT@Q)Y37* z{+u;T<=cM{1+UI&kphC;OP)S&{Ona5p_V)y$(dbdMHoB6jw49129X$I@?&RlXgDnx}FBP_Bx$=P*Al5RD35SUe zsyzF{YYoGAhvCAMmHbqIs6jlPm@C*He-V2K6!v)~`Ob9dl@a-14t?q#HIJYQVzoqz z`(t8#{8B!vvlTCh+ccc9KU_fDFAtLi>~7{L{HxZ$#8XLXW^u;C%?jy*aJQ=qA=-cE z6kqhU9E2^XJq#1cB42o4oL1_pvjF+F4)>vf^I9aAsrdZ0-N&eaDAMa_i5x{$iqM;` z_m9{UFEGryK#Y&V4S#d{LAk8W@~3*GPqqt_ou6g(NE{m?Eoq+hA3|w+e4;Mm2kZho z7*ECVc+?z)T0gzPdwlG3@>dXdp>!M0Cj_h9zR7$qvu`ehEm#^skF;~JBMiDQOgTKi z=R<8;C2a)h7bGTg$g49pFO*XJN&aK?7gsEwu=gnvML-kI{_IU>5m_ zp^Ro1IK@&>aLc=wd31sVF}AI`(w#h39yde zlvjPOPVnR}YLnFo#;Ef3V&G8`1J}KZPt&vbEohg+G_Lv=uZ;TWJzTaSZlM5y|F<&1 zy=pQELfrUGYUJ`H=tZ$U@C_|tm-Zq6Z|4YlrnOnLw|aw+_mZ?=1Nr`B=N^5HH{NUK z-t#Iop$o?s{Yk}Bgs64CfIq#~ny10pNlib;0^z2!v_v4a4a~ryXW`i&NH|ZQjoi!hoS(vGl-rX5hlpM2#5JVrOZiL4!eM80F-=7`F+p z&em~+CLKIt?2kw(dDS{@YnD!pB!@9Yjqc5le^wJ|@eP$`)|JNc9wSH#TpMc!8*<|y zOKXkDA>|e;cb6h|V8II0Q17OJZ^8b_%_h}C3p7ItgqI1TWsi50z z$R<|)8lB^h%Agc1eSpytED#d)Xdva2C1Q1UYp#YQ(u&i`UiD*??TRl#Yi730zJRl3 zZ6AVKvvUpf%$;9kWI&k1`%M@4R)V~95rStq*50@b&rB%CBYvswJBUAX5CpNCUjiyd z5XiWUzSOmW(F*q)Tk!1o>`ENx+{~xxggIW$7mq*$)i}(}$O<_`13i;e3fRo!xwj=QEFQb~%nV?yTmH|8h&m;@*XSH%m~F>)Vl z)zL!b2HkEL6w0F##DuO0(r?un(9YnsKiyWEmg#V5H~1}iK?-~Dir39%1-^ZP+aGm; z-Gb?Z&)1Kd9epp8_N57Gyb*FaJ?$#n#OEaDHy@dQ_C6MoTvaM=l7@wXtLTquPWQz% z$Sus7%L{EEj#M77mu*;8(;G0-O)@-8-_}C=@1B8ZI;&LO#?v-*Y4h;(&oTbG=k3G_ z${^ehC*bu#a#`3lFyzsjD?Ro)krZ56 z&J3hQn-)(FQbP8&9eIpDY=bNM#sONI-3l10_~3}@Q|VM*R;eH9!?Clane_BKDo_az)q1y}e$!6iWm9`jd30 z4z<;asaWE+nz5r8hce}k&&@54SPj=2ckOqQC3A_PS%FVUN|uLv zdWZ7+T!J3#?}4^w>dr#!Z{5B3dK20U>H7i&(`_M^Vt$ykmL-VHrb5NSnfs(Ev0uhC zArH($UfO6uY!i#0nvc(5S8qe>OlB=p4i5uoz4m6eZjdCFW32VDdKsC$)F}a_blnPR zB4_TXzY3T2Axrozz}+8Z*!U*gY6{v`<*=>LN$Hs%P-%G+Ci|cl$dNSUfi&O?-xFqm zC}1bclORu@%wC!ewGwM&L_b@^6LH-1@1gd|wt>-$=jlBgB{R^57MQ4>CGdHEfL%eb z`6C6MFmqnpJ_znM+0~_tV9T&XyeV%|CVIg!u5!G~M7_{Q2=?g!#sPEUgM`HrFi>sB> zt%25TWQ~#8$Jun^QeMHEslleXi@A%?lv`%Oo77ls4DqIu3|=%lrsrVTR@ zv}IW+JUG=JAoBULaGkBuWvR_IeEV0}#7Kf^WLcJyhi0M(f%?zcpTBY(5DK|63<5pM zEk*gu_;!@xH4ze=R>+w-9sgmV(_W%~6;(mZQUhXyHa!qdCfhSoBbk?`eFPs)MTq(} zc|>+3?s~FDXKzu-Jm$WNXSL0F@DOQF3g7(W(uaI%0*)F9i?Sz!;7!`rpJ1(JdA(Yf zq}(gzaxtx$LWp#FmmTi!zVls@ho$3jp*R#6iwMh+W);8XM&x|C#O7tsXK>EOAlcye=);)O7Z#L-eBcG>gi(;J7mz+Ls$j}9YExskQ4g+Q#A|+t=8~= z*(jf1k4A`m%EGP&!c+WH>Qj%XTQtUoNZ(7js+QTS9ZJf z-HG@UcxiCg>UoG6fiLEp!H8B*_d|hIGvT}_Zq{9J>`&?n^+Kc>%-kF~iF@;q`q)FUG$yy9 z1NDK-@K{1MJ2B=Q_Nd{J|8}wD1Zv9y&IC{v&J>BXSh+#0TqC+UU5Ny3rf@0Lk}-PR zwVq5=d4(t6{*N-{!44np2yt#=7ac$EP#F_oO(+Yf#yO%fY+P6|qaT-g>tvR;B|)p3 z;W9H{0k8csoP(z zyD{h%zh|mKb}J$`krp}ttPP#3oMXx`fuf{hP&+Jv7=?FmA`XLyezx?$Oem-1px@hf z7liLlQWqRft7Ge5+5YCv8bW=!R5?nZ_QG5;HIBDSxLpz)geBum{w@7&dB=Le?039Z ze9b@{+6`yn;@`iuqQR^$Nt^xnd7b#1k9#`NCSFw2d<0Go67krh1nA)N-@h+q8FD^| zi&ug$bQyZ4GUNU0h^rwajkgTb@Nr15OSL~>k*c|o8Uwos4xIVn;~Q%5so4hL z2AkoES5b!J{#|fcmu9%-5EbCl$SrGFoTfBe3n3E_7hCM2cBeOIG{H)=4P$#vqJR9T z#KS4l4w2eW7z(L_5G*6s+oH4;KqU7U64{f5hRk;_przEErV>YimO3T($&{^KFU&0& z4Bq0CVi(Gwl69Y_Db4BLxG#=`SQl_&{N&6+!vm_XJ-k^=%=2zAQRs&EnUF%Hz_hl|>dvn#8q!`x{Tiwfg%fQmf59z8An zEsbyfifv**N*A~cyyOu9)}%~i!_td5kPwmF|0(S>4I3!w(;7kq+{iJs4;k*uJIDIQ zbRAU7SGDrqYN?vk0Nz$zym*j!*T$Wr=fp&U6ao@8B#&yb9(cco!XY5->g2j`nbRGrj#+vFKx=M2Vr)Z9sVu~3pUBcdCsp{$5)}&tXBWh{2 zPd@j0e_6B^oE?d`462)J@3xbiC!thvWA}YIY-ECDIc36XCZX2v41E5W5-3I2|MXWm z&NFO$AmqyDE8;Lq3z{QzW#`-5FC-RicA41|95S)Cj2@ZNz5uJvFCdEEIfaDieCdmu z8!$Y1fLzVLV&Y?K(xc}PY1;IBf~~4!igxBFR(=$z34}B>i890o%<@C(nv%@|Q`;|C zh17|}#9_E^ga*r9VC!0yj#LPA*UF(Wwf-m;n&#!7?3cL@wPg(7I)M&~Dj6QG%O;5m z@*E$TmA`$?Z^M~2%%2OzZy^rYF6Z5nOs6dbph$^Y|EyOXJ2!WHN- zpQ~Wtk#+y9n&+-17_Le;5~4fYLa<9+Sv}Jb+csy2v8Uybxg}Gptd@P?GbUmy79||S zxdjUUzP)}(Z+z8X14rE`T0`}E_9cAN*NYaFraVGc2pM(0upMSKwa3) zG^e~Biy6P2wt#78cmI0KZZi;h5>47b{CwoD`40}ql(g4u*uqBOJ^<$ z^H!HrH2vh}qpL>IJq#u)j^L*bzomZC8=ko{);*1;=KvLS3(n2adFRbH7r^0|Po;EG zw?NA^qtn4EeLnS}tNILVanznSIJ!4s{r7WzMqvq)x9}u?vV$^3{c}nneaStiXKeAQ zzfF`5-D}&nPt}}JHnxek#_F|N_Bj1syD%STzvbXf&B#dx;5>{Cvm#zXt1O-U7;!ZI z)SnX2u!>ZkoMs;Owu2o5fK_<&v$#VQvZ&`AKttNbo>Q(j4+Hm0!0Lz@rnskVJvuT_ z!&bN=9=b`;Mdh<}*RqOI_uO)nm}PqaWu^%`4rCtkKXLmO?_*H$heu-@rC6 zZg*_O^4ffM&rU!o7Gn1Y4WIeS7z ze+@WMnKE@B>h02G;fOhecPtq@N7M!Ac@%An@e(^=sTZEMxyzzd;M(XkG*RQo+gU!=&gs`wFgohykK9rLRbu%C z*%lXzY5g7lhEQ-<5*n**<4!1BCXPIH1b^K?joEj?WNo>w0tnrdGbki_(`+Q5KIJEV zK5| zG7W9~k4;rCcZgfTfD~$+!Yw^5c3l=lm^Y1C8MXa_)Z{ZvtCpn{g)l<7gOP9^JE=fy zj$Zi(JKF~vQYllg88b>mZR}~Fi^j|*#A4RdgZiP?D-eeDP%&52he>>dZo1|3Nl3}( zS_7f&F5II2yR}<4tipouU0fjB!Rm7GOo7dZU(K)}gc$eFQW8RxSm{LAeyr{l119Ai zG7dIW?jJ7H9r^dqzwUV!{^?xvCf)ZvB5|45*_Cv!Q{7sy@5!TB&_a$tb^;3jJR{h2 zG+8v~CYv`sGEP}I!YLD+<&F|;I4Zti{K0}L;Vwc>wW#r*P*Acy9y6f3+anm2*I%k< zeOsMRWfDMBYxvqh`Z~imJT>F`B>MN-XoQ9PDfOE9!_Q;l&RO~M^VY(442pG!sCSz< zaoC08(k7~#=ZHLaf&q$$L`0g%RfBeW3f3>I0l66GeYHEm9a|T=S37kblr-l}OPRaw z2Ag#<@!1c-?2$O3)HWHed#SF(QmLNyE=PorO^wG@NSv_4%{k@)SH8@Ua>_EHkskfTgR%3Dw zZhB|55LE0(Eto_UR5Z<9{UV5OEq1sc&k%OXcMW`E&^8p5S}v=a;IuhE>EpaiIE zs)8yKIKuYv!SFs+%dd{imDhgXYX+USdivn}&HM+7bSMw&g9QMR!8gmvXV5#^6^u z3(i?CqpuB^XgTN%HTFm5?M=+TGP9B@$xWlI~d+=xRzk#8)CJbX1g$9zuR8EiwiK2}3TY zX=p*&sS?6QD24@4>^tgWRku0eP#H72G&-CVyVSrlY12}~xwHu(up+lp;$n|DMxBcd z-soWEdjV`^G7rrYJ9)Jp_^Z!s;&uz=Y7Eq$C}+)v!i0asW+1GWA^`rk@nsQZucsc3 zDFDyogOg+mnXHpjZe1tI0^JN9Oh8N{m2jNC%-P@;k5-MKvDQLRxQ+Il8CvS%nmO>S;xJ+Ak+ zFYwqVqLFu^>j4%jEx+$20~9xMA;FP2PymZV`6%{kPYLM2r{u5)ZYUY8pzq27;?xCo zm&vANAe)a%LxFA~bFcbjq;g~wykbJpM~(odyvL6|IDw;7=P_sQ!0Y!nZoU_i2)iC1 z{79r{C-UJ(G3#Gt$`m$rwjjY`?Zx=y%?#^JuwP*r$HXm@UA(nM>v^E%e9#y<3&{OW zK@J5W!fV$0p_@%Z>i60u4hT3ASoLXD4hp5#M(miZ&btXwb*veuh@m7#zESn7DEjc7@ag0UZfUbpF=@|3k@R%ikc(fEV6Pm`&>95z5th zz{HwH$!`oXPu3!&Q0Hnew1G1&6(_+1Frao{a5c}{IkS#0XOW1jtoe9tB(wbh|M!qn zRJ#Z_zGep&Lh59BW*ye<)@%)Ija1qUlUd3zOf~7=jCbzd9&bqGHNXww=a#!Vd@Dow zLi3FsnelSRH;fNn3qTy;l-T=i{7P4$OcTxMB8M+}G`90f3rolsrksM0T5WPBu5zh& ze3AfNx`pzrc+>lPm0bkK_Fu!r0xk0ovDsgdeg~h7H3S3ZAiCG^OW@T0SJ=IQAjuv; zra~0po>sjf8MZ)h0H`$9j+G4X0fUN$5N~Q@#{LCaM*s1UzmgTS56a3yOWC_ zG99FB+AR(1r9aq7eJotZRx$B4Ll|^{j46TlmrbJu(n7{emzb+D^f>5|X#fwK!dJ-^ zGP##*e5{FnRHs>=S6#UoNWECY?ry=C???5m=_kTy9dtY@PU{Q<;soqqzkC34 zgznbFRmFe!S_lk<77u`MYSG}>1|1To$OE)CUs*^a6Sw=bCwb%QNJ0_idies^5_5mK zBUJDU2T8yD9}eZz!kO&}6)f#=LWLfNO$jp7G_R-fNpA?m@*r;gQrA~$ta1kjV6%aeW556Q9z{$1d|v+* z&FjuMru3LR)F6-uDd5nlUBCC9Y8NwcOKCUtIq63-a#xrO$;qBH`@w*+8{Ccy_WuLZ zKrFv!lvY3vL+g~TT6ZYrF#Ctw zTDyEj*N3U1u;j5oh1}+LB5r(6Vm0B+P17(VgeYeDDJ*g?g&@2a4EX5u<}XN&P7EE%(mTLS`wF1c@Uouk$H#-9qJUFCkd?{} znpC!@(xZv4UTDmuZ6Ztg&wNiMr6QMrw`57VKDXvlN?5|4YoMz*U*$Z;H837#AQM*4 zms;=1$rHu*EZOK10M=}{iy4`H9UE?TZ|nbga-P`}s5sz>fjzWa0%UC?h67cH8BXRx zDU*UHE$5g5xh1ok8;{aPQA(X8BV4)<2#tJN(@UE?5yta%E*92=9~kX<3Es=SDr)^@ zz6T8;P~_^B6ee1k*M1+RRhlFCL6}A^$eNxrkXNXTKey90;ihTZPTR-z88Mh4tla);3PXL6Z$5b*`$shYg_}QgvS4 zC|LqONVM8-MU;nB_+-4kLRyNTR~671bwe7HP_l`DoROObxeHr->eM-4-G~@WnvAm|K;yTgQVccAr*yeuG>aG%z)YHP$V%}A5R+uN*h1vD8Kb?-NR9M6AC83* zk4umC0$AS6SlmrYaduO-Br^JAkFz&9G#f^9nQ-udUWLS_2SqU>FB@SQMD4#kvSw-t zcy1~!DOoi)qB@RQZf2ZsLuHckr6-4F9j~=OW%b zLVGGk-`%5Qtj@#%%&K->&aH?MGNE~+0w#;of8L?fQE!NKQ2jV!P@(m zTZdsS>;*qE7Pp2f;x%4dBCb7lHv-~Pt|{%c4!f7$&1hY9l5;~if4!)!H<#jMR?4%^ z*YN;Io#+Ix_O%x$T93!_Z)w$*rdnPn`Uu%eR()Ix`^OJcd$H05fjvoyi?)y?6lYo1 zzqktZeB`7Yy1TB{1WRUD%3PWYX|>mEr5$8xrByX7Fgc1SZO7CBEA1W&oi#P$WR>=3 zqQSvZUQ+6=FQYuarLqTR>sB%H3(I6&JM`BG7jKS2?Trrpma0*!V_f<#SFx}xP96X- z2x;XiL&v4bNhFr`TWKXifoVbTgE%P!i1V#ZDWWhh^0Glj5DPTR`y9!4CT)3E)-Yi} zITZ1-;yi;Vh7%>IB*dh1F~1jHpM#6it>KDe4%C)szAw~d`C!o;Xf_OYD(k&`ju3iP zF<(2G>q|yDNTAVS{hXHg?BcY}d&vG43G7AroB?s%XPO-)U{l8-Apd6>`(Xz#NgyLP zKuXfqs{|t29V0~vEYzB6&46R&QH0a8cXez58Zc!bu6zw_h^7W=KqT~2&`{=@vY0k3 z!S&8fwfSvndnk^%8-VTOT6UKt(@$Bl{^Hoq==P-seMa?mqXd3)$zn6ZyNS9#?>FCU zB$K~-wntnCnInw`L^3qUJr8RO86_X&Q?2_thF2xbF*g_<5G?LR%@9ldSzJlfmgal5 zijlOZV>KQn%T6`(lD&#=C8=GUD~P8yXfIGViDY>I4PiJAa4Qcyv_N|{!fi(sF&wFp z!z2*4aPX@J?cH5f*Okb2#<+Ia-Eg>glPJo%5jc8MoN4x=+#MH$?IRAu5fBd;C+}*p zem-LLp4&hhDlHn2&ChQJrROHFYo*rGO`=d`^Ypzq%4HK~Keh9U9o6j9;$ERu6Lt^F z_cRxb#aXHf_PLqpuap_hg&6;oGKP~Dxg!i+al++$=E~B@KzqqGJIBERo@>U70pvCa z<$W<-YpLrKN8eWmgjC!|vIc-#Nx-By4h|}=xJ7#jTzikS;B$kB z7#2apk~IVos88@QBR3wTr56~)iCOl!QusHIb%;w~b!*BTPXQy;@tIo5w(TBfJo2VH z`29DY#ZSKbEx=iW=FH*Ad#}U$^6RjCp0K!Jw3m$Rg@U<$CP*8t1Z-comV50;T34~$ ztKAKU-NS_L9;4Yfte+bZJBQRd^v6zW*)I}OE1B+6FIm<017ZJgS6M2HyHT9nKp2lC z13n)5s{7Dv#d+zET@4V%mE7;tiFn_*CWNgBTJ0VYb$h>)?{g7YoN7kSOD(@-)Ux&$ zXZVx~Dp-WDpYOMu@wG+SX5_?D<7!Mrw*S)s<%5a;BLR$pl zVhPac8tC_c>lta`v@C)E1W=PP9Qhh}7>)v5^az`z)N6H8hK#UL^?q%OS2RX)QQtlm zt%P=y5jMGIU+0lb$)M({YF$dNN(TWql4jsh$DPa#RBe(v9uG+Bfg|gf700t^+r^bK zPDaTdms( zL`X8Xqq#qx_Z@S7RW^Yf3d*T(NZa1E zzxBLSelu>yD`XTWtjd-GAOKFT zCFMo*fKW~+`N&$K29q9k5CqEy`Z^Ulu^@KbI2=wjnR8I+Cy<2-q++62rGZ}%!v11E z@9YJ6N&d7yG;qCW;GrJN_S%u3UlNtQhYbVu`~Rz8JWV_$lR!p?{TF$ROZuIl?3ay{n!{k6HX!ZY=2@+eB&t~vN3&e^DT$*^Oxe*L&R}=5uBfdiU zx=T}5miqg{sUFNiICa>S8aSJexdrHP-LS)WJJjxjpK(!Zu%z}e{=n`QMf@6id#|0s z@1=Gd=jy};)0I>JPjBfQq^h~w>-~^ftsm(*jzYd}Sb2<2Fm8y7D2~E+fM9nVDnGNi zBCnfWMD@3geC||__Vn`A0z;sx6aeMj_7l`IwLpAifD>SUxxnhTS}gAs96dEw-l`h| ziUha;Slv&&zZVmC8D{OIP+x$%oh$=>Eb4_;LkPyP81fI2E7d!qQJ6w)*fLtmvr8p*xTzds!Ti{Ln@q&ei?18w@ghQzU zB>@rzsiBIx8-$b+FBOto6k_bgjMAEL;0#HV3#3rjB5UW|scLlX1Uq0@3w$GJuIz6TcffUpe+TPCJ)HF?=nK+M7KRSQA2F$}R~9eRJrbzaQpa9lZdK-FH6eBx5) zVf~#9h@wM^*nUf02q&5q_c9FTqm3lqjXRMyf_4^a4LX~pUFRA;n&aooR1SOxT zx0fPQ5y$9bTAQHYm|kPFt~PZ$;3$qqbejr_>i15Ks9j~?T*|mMXq)P^xNC(B7A1VI zqNQFC8|pX=N7GrH7Ay$!emi7W>RDr=sks4S^pGZF`#NCtv=-fZ7T#d=1O1-GYm8yG zd+nq{gQA5&rD%+54_bUdUSu3@1pp0--{5dNU^teVFjMzHi>=1@x9fVrxFPbx1Og@N zoRX!)Cc_n7;761?+Ttv9T24&uJV@Ra)D9(Luqrw6GDW+ zhh$ZKbsjNI2QOsu*ETM84ubZ=Fm0M>1gVwbaA3krzfm5#aV2>4ZO`IM9(fY~?ffx( z{P{Z=pIc%$w%0T``lO(HZX}(n6y-##CvuqJYH?K<><2vzdqL4;J~e{0U@~&eZ@HeV z3TL&T$+)beW--uCrrJs60Q9#tnU8|oA9e`)%)@xW_v%k4ex&aOa>e8?>=OJ{k8019 z60mMC9C>V?V6a4=Zdw!hVG>-bU8WtMx$8#_P8!6;Bq}B&@0F=Ho7ym+8>{lgt0MXg zuFu3uJ2|5KH0fX)yC?EVZet2j4iTB>RB!&ygGRlJKM)X+M8IXH@zX_v!>!BgP{VVBs^d&xrA zc`YXP*AVV`37q^kpZmB5#-(69lG-IAL_4F|Mt00R`ORtJDuu-~3M_G-{J1rNY(<6q z)MMQPW(5@X>S--dWpQ#x-H_SYRAfef;%c(yMkdnZ+H8!-o%DTzf264j|Krh=ocSI) z&l&LgJygAX`m6vgz)UN`5*xE&OPxbpIW4|1VS)h7Hde1?H)iM&3YF)k_cmesDWINO6}G=@0sKcqD1{4FzhyB1CCXO3EG zi0gv1D9Bwwd*NC2nN6p(R35ZA7Elz@JNJQ?!X&plCoDKAQmQ|4RdCCcy@M5D1JED) zX)XmO&`y=kQ$rZHefFr9UF-V?GD!uid!r%=ycR7?yTQ%{6(P&&GvA?h$o-I6^lmA>A=+6bC5iV*a)IkJ zd^Z(VLr?0>{%*jyBtnAv5!~-Z6MHKl_eY-AgS{z+>!kve&NAINOFEmYsOPFf+)y}m zIJN?3(L`1YoEn3e{h~Pu6bGbTfV3I$^#`Q;OZZX6ajSwlHt@{&+%(xP4}UQz7uh=26l;$xmk& z#d_`Y7Z%J^zoIx6x3idThSH4`1t(e*^oIzUQOj<|t8?6xW^TsKxEVL&X55UMaWihl z&A1si<7V89Kg4m?p)^3rv+3X6& z0FQSEY*g)Q>;sx}S1o9^Pq5XS!@BywhO42f#K(oFxQYO|BXmvgUakCB_2!wn z4?7a5VmQXl9+#}P+vgsS+2sJ(HH@nQe-K3k7;Lpv7`IF6tR(E3q-B9T+GFQBq|Twe zasUF{*iexk83nX_8;(>pJV5q|{yVF0yrDvxE8xLz-p1-VhsFJZ#k~X7aur%!J8t0T&y9z(?sG?70-`k%R`&&m z<9?2q*639XID&n|Hh%2uUa#9GI zO9~=ccd&RqulAhq-5dnXHp3rM6@RK7$6U}{MdY@j*S)R}-xolemRXSuR8yxae6!Dx zGFe0Mnd$w}E@K!8Wt|IgK?n=Y!NHs*oC=MlrLTfhRjh7D7;!~kw3CQZZkLGaFi_$D z25Hr~pBv5ze+X585-=FAQ#yopNQE6@+fxotM6B-Y@CA?D!>|75H^V>Ub-(5YkyM;< z4&x7dc3iuMPS-4<)PQv_+2L%@Jq`gVrxB_3m1kRTQwBr?acKyF$&sTvRp^`~O{yqA znPOqN5u`Bra!>RJsoz(!LXbN_e8dwW;022_+Fgw+LrMULM?3hQ;(`G8ohU?95TO!v z{b$6MG%2G-70=E-pwG5-7*0E-!6;f}C>2Fk{nJgwdUjvfou1Kq^j>A{h{lS9FoZ^_ zYX3p^K~XzPb1Z08pwQ3=24gqwJwLarLZap&KJUC!)Rk+n+Sb|msLw1nZt@j(hM?p8 z%eqe+3dqe|wTK$i`6DW3SD;9<>3nn15KYFFpP_xs4t4hIZGOfTt=v+_`$1X^*Kl#9 zZaBN=dfnJ@PYSyUk+yiUMOqZZO(xZ=*KV;QVqByEprJ@|D{3z{Ju6ZSrt?cufkZ*r z3sG7RU3F5iPI}nu87{zZ+Np(Ina}|W z7^_tRsvCqMd|vESb2DDO<0dh`88_n$W-|`qXyg+fNR!7Y?!S@NNambxXwUX;L9tXq#LZtDcfN*B}6IC3I za62Bv#?|vPxMP1x<=Sz>f4fQ@u7(a}8|c9vn6&qgB)Gw&1d0^3myXKMQ0umC5?IM? zL2gx*t6&oQDONZ@6{B%^vWc?$JZuORPMzMD0T|bq_Ql<%+K3zrC6 zEg|Fek3PVs#aZT0w@ibBpPVG{r2aT!{Z~nqLI4U16T;&tH zNGlk6nY(KRmMQt25?MDY6!M@^gBK+A$3+3+G602%&ZIy)#l21w`sMS}d@!iB6?0Mx zq^0ri1?y)Mn!^NBc4J0KOrGMxU-M!QTj2Pk4#%H}SiEq6zc}!FEdmVsZHoPpz&RlS z;xlsRk-dZ8N4P`6qE7%Q$`iID5EYi_mdLF`>O4X&)xxQMR|}Ly2%UEdeH0C3;>IV8GdA9ZXUYhCQRIP6)JRB1KcL)eA2lv z%nB7^$-dOY-0!n$9gzN!^_ek<nN|uunMLX_StEnq>PS zQG;P0kyhsYEj7V2N(W|1&Ya^}yy%e*ATir0NoBgP2^-}$?opNI1QmQ&RJ?QNo@pZ$IRLFifm=gty!4P0~ z*J1GxXdjY3P>SQc%%a~ZK~x1kw~mDX^AmTZen=|lPg!V6UAR`%^0{!|5=_wN>Izc$ ze049fIbZiE$L|rB)4ZaERO8Jo6+S#;StQm!>bMenK&;Pf7oO&4l0r9#ui&5Et4bT3OH#|`IA)aQClm!JS) z&myeput+Y5OIn9n!7vBH!fV0W86CzZ=R{xgdp(2;uz8+ydH;w>2JoXbKE56H{)i!LPlCh z4VsH{>VwHdP@>s;X&{huRVmLc6UyOkLT)|ABY{77G*`g-*~u;pVDRSqjP;XOa2I=& zu7wegIB;)C4{UAnZI2cMEo}OISP`u(5-B^lM8P?; zIs+VB5V*0?qRg!8)i7}Bj~$NwKTqR-x%D)j=+5we{F|@B>3e%CO;-|Ty*D-sU?xJA%+#de^CDO^7^RV?*prgV{yVv39w;kd#z&q;#@x3Ut z1(e3a?;=v`aP~zb!g@s8jY$9J30C(qx!Z-B2FvG1_>n?LmW)_I#pXdCJ(|lN%V)Oe z9tMn?MhhFRcF+8Q$#ystj2rU5y9c8dcpTQxFxkD{@zqZ1)u^3m>pU`fY6kv%`TPLC z9pUyPhLaO5;!M2VtJiphJ-htv#R$Jk7;be8c0~of#*F5CsA|!}NvO{=>@vbW!SA^? zN*h#Y%CXy(DByVXsR&6xdp_cDw?%*Afd6oU54sb45MPMSt4_s$DhOA3(V6>6h~yOy z9Wb0Y96c#m-7^8Ptk2OSi_jxTnT6n-D!`UuysTkR4%`rFsI%H3T&Am_KeNEKz!T_mCtiV4DLGA4jO@JvCW_@!ir z?qT4b(DIC+?u1AB!iEK#9-MDQ?Yssmu#=Y!T)f_+xhgCg4W;t8!(p;Hv?R;iI#3Go zszq+SIudBotaaPrsF{jqJrhDpI;;4k6QoT;jf9IHE;!^xxMtthUc~BfVfJ0liktxA znpU6f`7pizY`#Ogyv@0`yUkY|fOjnRmBy=g6B%JFTkF2GA^h~(Ox9#NVJ0C z$mzY}Ju}plKhPQ$PPEaHlxxmHNLu=;n8z6L^FROd_`nA~fM5RQU&cp1@)4Y!ongIR z<8wdvbMdGD^qU)mMELzU5oK<#+u34}9PQ`2O$ze*DU>{0bgCcz{PAeH3qh``hvEcfT87_GMr8 zyZQ{Tlxy6KSKi1bY$B-1CQMyh*aZf(i{-Rys6tvU0Wu1TFGx#Py{!u}_qTPC@bxNm znMzjC|D2;9{r&B!H>1JnxvRDAe4htazY1n+|(+YVsB)e#gp2pn302u*6aijS7E$NI5LKfLs|+BG2m=mq7k!tgQ^o-XHl#8xgae9;-DzF0ldnTR;hfRoBGaIyb6TELlBocNEI9XF>ro79Px6 z&i5*q=LP*8c5il%JD{wwUN;Emy}}lOtli{rAjQEQVuiJ)g?f0Kh?I5J$As!zs~vB@ zXY!mnhtfEtRRh<@DTp=!u$&=|T|a<9bAPA7uqK?ly)ZFEs1+a(*SM9G4WeCjc@4>gE$sDYg+jr%^s^;8_b_`DS^U+3`0 z-})Q)*uy(G`|VSlDrzCA#Zg)c#-o6;O9b-~ghPmJR2eQPdKP?P=8j4N*NNv`E1@LZ7AZzR8dk*&)-p92LGI zQ!>tVm9;=?!jWaNO|>=DOoEXVPUX2@AyXAaG41tg=C zsTKH^duOxbI&^6Utxu?XiOspXhGAzX?O2U&Koo%{*M?3=1x}qeN<+j&Q8yC4XF-ky zPU&BD9p?!lQHv}(|DxI$8f5|nTn9G)@>I~`zF2C3xY7{7y=smUxf!p{@vi zjQ{dq{>w}L{rvnKAN=44@xc#%5a0KG--qx2{_n?M{i}cVWxIxrzVGoZ-|{W^;UE6t zm;CJF;sPJ}$Vc$wKmOytV`Bbo-}Y^I|NGy6?cYB6$xq_Pe(cBa<3Il6`1^nV@8jFQ z{o8-X&+$sR#?5$z4h>orJ;=ior9$t_$5R|of>)TS9*_~VEraHnBZCp+VNOYu`rcY# zp$WeIH#uysCOpP7HZC2z^fS1wanwqIw5%!=g|UrmcBG33PCk}vmA`h_HKCX*gokZH z4j%p>=pN<@&5U};g?-`ydq~(k?a*J5b6zcM2J?|tu3kayn&cM9#uLn}{=3m&bW<0o z1|dSOt1S2*sViu%1nst$z- z8;{(UYXOgG3Z#yO7Uw4pHoGQ#9$^L*-u5k?*`44)zlMyW-`CC5nXOw>kUNjzh~Cy| z!HyLnf7&_l8KumF3XkEKUAD9;NNu5o7x0&sJaH5^1BhX~0EL)U_k zKSWikC+r!WhrjBXw1inyWGsnUH)mKYym%$>2TZEgx<+CrbXHToBK*n5nc6 zAOt};c#J|@9x6lw?E{bA7v#YqJPc?q^%7ofxP*v^?74R6XTTxF6;o>e8xMYS8Ip=WfSJ0}#Nd&t6{Q4`>RyeueE;0{_G=nBRo9um#ARGzaH zoQe}bbxBYrk7zdrKBMD=aU19XUP@J{j@8{A zg3mbg4bu4<8oRqG=!L%nZq$o0FrA=RzH5IiL~uID_h1$#y>c3`N*Vh5r(mY(-J7P!pL ztPByd2t2x)sdMgztkjQDlRMP}z-%36LjFr|$Z66Uaidyp4ip0^RokOfs#7tD{*b zp0t?N?Ce=frLz?+zWYA$tWyerQ3%|a>vyhnBPo@(H`f!G7hLRIBO1Xt{Ziu+sR_N^ zXVE=FY60E~6{gX0GhW@}Wl790E-v7l!=L(7e+qx$FZ>03#@(8~AtH1hXxds5Fl<;+5_jUN0pZOU8z&C#5H{zSW`J3_9 zx4sok)8Jzt`xt)qXMYwy`lCPk8Nbgz{>T5gCc|IzHD81Gz3+W^)0^IeU;DLR!+YQR zUi|Ve|1#e5p7-F*Z+J@$_XuD-Cx=5&w7Cp=i(h8qYK@6NQ6J+SLM925TRd%@~yAvb=@glA~Tp|1yH z@-=8)KRcp38?k&45Vi?nJ5KP_ZA4lUhIqK`YX#rD!u?o)ftE5kc*3xcXGsGHjUP`l zdQCRMmeB0>A|V_Emm%N_zvQW z(`sfs!nNwS6>n<%eAXju3;Gk! zdwCgaP)fgfdcVeXQ8WWZ@ODouv3hDxF18^mgu%QY3YtqM4dYta{nCi%=vO@!X9e9^ z!sTlN`ddN~ykf#h40d;q28EClF~BY*=WEyz`YxjYmyVFYzCeb^?spq1+z$ZaQHOlT z!S54L3YyCi<57d$35Mf_Vqlj8%Ceyzl3FWC&Oo2wM_0RD5Yf&o6Zq137OZks2)l!M z-*y)np%}oU!xw@GTC9y9MbqVmJ+G z&pnP7lQ7!iJR|IKwUYyY(m0Ik6^lA2LHXOW0Mhgvw8L72_KOBNCubP7!&|w<0>p(! zb48f7tpmIFX%TSwx(C=yr@)0hw>K+L8cf9H^ zpmrh6VktL*(FG;m+J5OxPU-_a=$J z{)tGTuHYb%g)u3>?y(lbafh%o;kih=MK3u1L`1UF()6hsj1?s#;U1*_+JURx7B-#aWG2!?wnNCGT+&f)$RaP;Jqfajn^h>MKW2!`9P z?#EIb;nK(~cC~`s>SvUxa0_5UZOkfSCRj-EO2YchdT;*H3aiejiF7Gi%c*2o zv!V^;;)Q_}fj**~E{N=b@O*COdwZ$$mhogU=}*8xT!Cbd;?Sl;i-*V%W|9%|-QS|_H z-X+Hby(k>t4Ox*49>^Jf%ox|9Y8ALh@k?84)B(ZGc$E(+rIi2v%YJX;JHF#P@Xg=+ z&3MaO-tuXG{@?!Ff5Vr2$(LZe-Qo+s@C)&4zxHb{%QXPtAO6FCi0}B0?*IV&;1B*F zzUiC3>G$+qUU=aJy!p*<#^vQDzUr&K3jgw7{!6%7C3e5x<85zy8$R-pkKm1Od?P;c zk&mEl+gIc@{;!OO4tx_8-=+gH>M*CKq-l7Q{qB zV#d`Q*XU0K+s_fWffeTEJ@vKKq`|7%%~eMCa6mZQ1EnC|T46kDFs@yNt(l){@q)u` zPcg5Bpt&q)_66&w4&?AE>=^(gWu#S$xDL2_JYe@4LI1z(CSm6!C|OXFgTLQsH&rkk z7sS&9e>@;vw7ByhJbce&<8Z1R-lR&bR(-ZZ?2`9^9;^IEH)cYRQ$cP$eRVett||3u zr97?(+uh$~=cIB&^`Oly6|tKucD}p&1?{$=y-ZZWKXthO$4z<_HOT@1StOJ!IQ?LY z^|J|^k6+>PbB}O173?1sdK51UilYK^*fGd<5oph#0Rlgh8-UgG`aU8Edm=XH4rF%OP1sCQ zfhfNi!67Xvs_1()l(x=!<1w5nR6sk9xuO1ob<4sw!S^bncGMEJFzc?^x<;Yrw%Z#Y#FeW7vmqqd8MkB-SU;Po?!8l?GA&NHF+=tv;^_k8NrUJA*9Pqcu)3G9 zxE}!lc8@kV+;SL?nb^9K-P~}1a{MW#=J#>>?71)@X&erBn+b`d#lvxB$OlocX7W9) zm^2*A1esOtb$iCn*7AOu;JKLgys+b(-#*@8+z7@E1ATH`C*|mH$aQbnJ{qWRaNzrQ z=Sh~gFWZfn2>8r;BZ?I*GgB}voqdaWfi$9Rlx3Ws*2b%q<|$ZI^~xsm&b6)g{U_%Qvz0$Opv zgSR&5&I*p696+&3J3l6k5kC}k=NbDu9^*>TUF154s&hmt7?*tB^}R1k)eo`HWiAA6 zq=I@LaDU)jH^&Dn^imiuDH6sZt{SBj37X51XYrVj z7mbQBN=@!4R%Ua6KO2v{p6`O@G7@HPZU8Dg7?&QGuWzrRF2aGD3v*t!b#hG=-YcRF zsi42pQs2XzIAW%Lj1%O}qrVlZ%fPr63?~{x^aYEDrK*j)UXe3~O7aRnR}MK7Y+(PI z%#Qa#h@cvva~VqK;CyK=BL!v`MAO*!Gpa_|ms&*I-{#NT%Tf#MxdDtu)9m=!_IK=T zPzszD;4BF7J?~%lV65|aJn~vdO*~)Bjbc`)G0wZi5CAIuYFx=g8BzFrvt=?q=ZZ6i z<2;HhU;o>lU452%R{g@yy%#s*_iuc*>s#N7cfIRf0DupF z_`~?bCqD7AT;uHQ4Bz!#-vt2pi+}Mi{+^R^0Qiv~`4L=R5Uw zfA8-B0Dk+of4g?(Uy0Ya8J``)4GOao)Z~SgSwUJlj2lnOtYtu61}4rkh_f4JP%90d zor=0RwZf|WC^uEDV>byuWmQ9sOLiOLN;`E+A@9w*+9hMfnSljiVhqC4J|Ld8NDn)# zj}F+J?6EvPAe}~xw=(+M8SykB91pmAdIf(xR5ewzcrmddlO z#=p-$1g*8~4BK%v!C_n=^L#vqcSH&hhf{8qr` zqXCG*Md?cbQB7KFBXhj zM<#=?dF!0#0^cWu9eM7)Pc=DkvD5%t`VnrR$d4N`*M$mB6|tfaMaEDHWK3}Th-Mcx zu!9OMPWQ`=s0ljPx(Z?qd9slj6M3kbnB4uZ5houTv3L;qSq}-z=SOUwP1t-YWAOr? zr#+)d{OLvY`k6%?=fsq-S*NP#XG<+RU>0!NnyyqGrIlEsl{&$=aTtzCnHWwy#q?Gt zQpTjUy_ohi3c4wBNV}1KpRqX4=+27@j!9LUcRkS_{CCvvU@%it=N9db<<4`T6DF~% zXNz`Gb(#gv7xID&MZ2`a+MPwT7nwZi!&Fq{ehWoEObJGA3&u@BT%ba#4a!}$H+BWx zdBO5I{d2FNyAN~^Nr`E$SgdFtavw>XT&YjP38@#ko!Rg$W%>+iztvo7M^U@%*U&>j zFdhet#~$O6S5ddAV@PN&Q4&efR>c!tGp_mmlDWsWXCoF56P6D$=|@VN@B`-rq0LG? zYN3`{EI`I3|9@Oj*vk@bf8hMCbF@I$AOD0s=l;a?b#N-4>IQ{2D-VBC{bqt*q4vSm zgj>|PBJ5cdE_0r;ahdH;EZ5HCITggtY!*VN*8seyaY?#SYSpEoQzr}6ZhuSv94u%zua;kGbp=tY=ail%x29JR6i7itAyq%BJ5*D>0Cb_P?K2~1#Vz+U+u!o zu2Z?>R-ntXbpUV;8*kn05K{xhHH$PAU7~9UdhcvqjT^ym0vzs^>b3&t8NMZg#*L*4 zw%K`7?Ho<$^F>HT2QUOV?ZiN5HDKXi^nLv z$M$o8qfekF!L{10f?5Uxbz>&Xz7<@)iESh)fQvyZ*QJW@G*@xr?rV3<^$B6?&^ZRI zR-9eDqW|}|v3joH&VQxyv`ZNezF>iI!{^gJ*&^&I z7`J~!aQTK%Z(`VKP!=@FQ8=mvGUJ+E#nchr&#t+^_ks{KA*ljuz$3{ z2bU++PNxdqRPXJ{hA(#o<8gv)B7DEV;y%!y1~iS-KozAx`h@nu0pZf);>}Ci+8jzv z(#B0-ka8?Y%M65!{gX#nKId@jHxt^kNc6@|G%zDwA$xKXW5>zbT=E9QmVPf8oz!e~4 zM%M}A!XYNA4Hr+oB5jn^+A2D9sla6;!%|GDY+AUO5iSR~LAm!%6D9#l;P(hT8j(6t z+JhB)GK&tou@)-k>hZoWaO#N-pu)(h46Sn)GKo?u54Gt2L1kiS5d|2Ij7+UxL%YfS zDXBTlRmM_P#mD2O?vcZ3i@0_bf#Cau^^-l}`d_#~_JaP@qdU`%mBN#g)A^%o&Z(EZ z44HiPE>PeOKy#7M-S4sb9};-!H>9jLxUoMlaFw6&I?d+ z1LQ#z6;cr4fZGkmr6{@sNb2fg&&v;}S{|mcGaS*H&#O%%9aL1%v=t1e1*zk?HVhuY z3)atMY@Qy_-rMqQIay%)!~#x>UfB!0lqx=%TZhA~P>~cBS+h^qY%c*87Nk%cA$uTX zYIUTgLoyp#Eyfz{p*WyDkLrG6-?u=V7L)qO0?*BORgXWk#QeGEo~wU9IXQV*u3=r{ z*S+p_c-!0FR{uSv1QB^j*ZI?p4}S220D!Ofim&*Luj#rDZ+qL@@Jqk+OZbof@jt#| zuW>UzJBAw~x`z?C71$MQWr7`Q0$`n}xMY>u?}7Exh2l>INLra)TqQIYY3e4Vtd>zN z6LZJIqsb<6LqRghJfPk4xpq}Tubn}I$`vLwC1OfGw37fQNTXC`)sv5^IEwkAJBm={ zM)_%7sBljcstH>LH`$B&mkY)dr%J7k>eo;RbmDuDD?#?I3aSwHYZY<8HIq#a71|5B za}^)kOkS@5e-^e=RX#_;+RyGC;q)P2ckhdv+G!Y08MMZA#^RpG@_xon9C`WLMF8j{ zn>!|4=_mtDfg7E2O|{6P9fx?nSFS?;77t9JI>YY*eCLq7uPXX}D4I-K_eMyMYsgz|x4A+XElL?zPNA|uT4nfU zLb(X=1JFH)aEUjxxkzxG+V5?YKA^np_EIg5Vy-aL(s`gy8mML3{Aky~51bFaFKSOV zD>5CXXFnGlWRTdv?-bha1qIi|qnuJSMD3Ssh~}I`u6)0)m6dPqp-kGJ8!C_ZFWlL!(AcV znMe$mrq|b?QN5SNIb?C{4l0~=RBInX!WDiYDgdP-Mkcao;*|zZouJFAR6gs%xsmYn z>E6(LxZDoaPq@F+v3sSqP>psRZJydSUF0(>BIwTZWa+4T5C9cD%t$L1e^6M|DIOS3 z1KirfjV-zdN)@pCoip;PCC#FnM5#e$=0ik~`=b}qE%1xLT-aJb9jXIwI&Fr5y1J)^>Bje{Q-(;REB_}s^h z$NrA1?hPgIk11VSK>z}5pU7y>95$asg|9bTfgm95JdQr;D%4#Hh+@(89FHdT@$O-) zf?eCkTNM&3lcPn?v&Ti5#6dT0g?DEy*bOJ47L>CV(`@}p28yl+FK^s1%B)riJRhXd%2(ixgQg91F%xL3_@m-l_fqz-{>BMP0RAP^DwIn+%|5mpnB z9#}sckroW(4K{4ORZtvV8@4;h;2Io)ySux)JHg$8ySrW>FG@2$GHjMcFW&@#h@G(kXgO>g4N1sw)kEwsBD~*@5up?g*dF1^=bh4M z9_#!z4alJAv_RCa+nw(5oY4%Qe<0>^O7F`#F(Y9uI(V@WEK^i!K*RML`EvO^l8VrZ z!-bv!%gr>5z9X{mM|_PEEOuk@?e>cgGxb2xieqg-v=8Z~i)izXLdGR~F_;=>0ALFO zTwEjv_nZbupSmlq2AvY)mCg$g9oY5BxYA!Q!n_zUlqnEXasP~~s5>#QAGp`{E>8F| zF&IWl%={4kXfb_Y-~~v8q9bA|IlYSLgmRO5e&d@NI`_OxDu1p}g!+S_u7g^9z@jYV zf_2JJhRLVP&{lscv}_ZVla=ic=qiWqTg9zG*hOkZU%HWtLZnY=bvN^pVX21pH>w;> ztI$r}=|c#!-DyK@J(FG&Aa5RB2d!4?s4)f2_XRP8;CHVH412LA?o5DOs+OWloC|IVmuQ0mSIAM6PU(F`pT<;7=_st|81|eioXxCpXEDs-c&S)=MX}I%9jK^|4U-3wj2Ba z#a)MD=W=0b{}G|ifOm4Q4039f<(@{62L@G$T=18+K#lOrWqtF=I*N2T)E2fw+;A6RS3AN_h%Hh!-r4W^5ILVue>-;*SL z#sKU>yhLAi-@wG3*E?OKL49M$tlfZ+*q7fs?_RH6!4F_i&(Sa1!eR8+e)L`0;D55$ z5EZWUG0OQd%0aYk2R>ws#Q)s;RVZ2HnGRskY-D7#cXD!qMQL3gg(fmDENu>!zy6=IFO|GB)+%uecP+6F4%+#x9`Bl zfF<(|d>iqY;Rd-Sw&lUx>u4c`(4Az2FA|Ig8rWN9`7Dvncwkq^XdWj?%CBvSbi4A*>UF+YNEmQG`wB7srN^ZCUa4j%uu+dn%iI+Vop6ft zJO2x~Mur0rQU{x;MsSxa_8Fn+$&uKi#UT+2R&(M-&1` zlpn_1d8R5bDA<>L5P^SV-5S`>BW`%-=~}O1)C*Ra6Nc@4p;jK7buAGwmO{5g<2G%5f#DaYEjE+H0z_+3!WNGb+eDcW z2w%V9kBS9&T48?&3|bf4Y3|6fQ8cgU`^BsZWh z$ijYq(eu?TwxQyrkcqGe8-+IU8RzyEo0c!w;>$d0&2j01n|Y6yH;oICNynU+xI5-v z#%~iT-`RY(#V@8ppZ>g;Z;eQ(CCa#IbbVui-qIIuUY_}(^b$Sq>4uT@ltT*Dk=403 z&7vD@car^$NUWrYK#qG?0A_>n((by=Ko0KSJM{1t`)5?~3 ziD$_O-JVDU$;u9LZ56?taGPvCo>}$1eT}-y(@orxas}7^0D*cm!k_;cxYO622U=U!y&bQsLF|~5c7+z>*=(U9!OR}V7 zvXgNoZh;b%{Vqz?A)*+|P=HB1ALH_*!A8J*08S#1&Qr!n+QYaApn?}u9JYa6&giJU zG;^zjYxF>qBnYAvmlfnSQY{c*W{%9iS)@$AgPzs~J)^qPr=0KlcLx2@VepLkM=CBg z(9qc7)01x`_{gc_xK`0wNc7Bb?x>=)MCp&KffP6TnWoJDKU)Jj7ki&Km}L8D#(V$t z6zS{l|GAukW?yf1F1XzaXdc*59-CNSI9@kr-#+I=QDu#ohdRF>IggUQl?G!6@2kEd z{tHb0&!O=6tMK*Lv%foS$A`MyBje$Jb0kMgiM}4BWPQ^=T5WY3?NT&{W+tGTPJ3u3 z3y?eqyT#^NPpso~aD8&7(U7s2_I z%vpu^=ss2yNnj0yR{vP8*b0!qfjfG@K95DtCOfx6fu-0x5{}gGM!Lra z+iKSVVR@kwH;xREx4DX-|2?3$*bu1@-8FdL9gD}qSUA!}P)XeVtJD#G7C>@L<;C+i zS3>mEHRI&Nd7{YUWu~z;LG$ZJj>mK&zW%vPd!^?dx+CNddqL~o>XllVH(9>Xey)G@ z3sv-X->f?2_g8YuB_iSeu3z`E;gPlT@NXCDFh>04gvni3dfj3h&=Eod=kfz7>A#AZ zfGk#AnQE2fbpa`Qui|ifIh3(&R_j{$!mGg5C~?VS3FZE~{@*{ROVr+7<*iJR?P=S4 z2Mtl1>aX0Y@0$R-T3rK)p;!Lwy;r2FZm~qs4fB>9T{FFO zn@uWW3Ecf3i&wXq%aeP?InV(OI-E?kHn;-1tH%AOAxB?*a{E;}aMwW;PY zyLydic_>kXHW4`g^Tjm`P^2OV&FTV$m~&`KqWBNvTOM(j(XP+2B@J$r?ix# zIx@0Jc4aY8!m3TYy)xfwrGw0^$#J;xH}L64rP^IJkBMGUt^HOfm<;EQmmKHU(ewFh zLx~o%%xo03;|Nm7kJCax=7NV2^Y_%Il98#LESPT6%eS3={y?Nv`Q_>q{jUdi<0M_m8t$X(YF}UCPZN+)O zKbiEUk#tBGvOVf`TwQbIS$%&A1pAvPPaGdG_Ur*2ljQ24rg zYl_xfzI1J&GLsA!s9NylBIdeG((pM)jVH76r|x%KZr%QU;PcXR=&OHb$k8`kephDv zWTerwu)}6eC^D98uBYDJ`@gusPJwW{D6=TEkCE5vjv}5AzktQlASPNHj92~jnvk-m zhYpzD{182LYuYnBEtxb68-6CkGED9}x-+EKifb-4j)D$tJQMYGX79w}ziHyVqf~I0 zc&p=L5hW;hLeOyrZB;5c4o|Mo_RC5X;+;B@IUXB{FOuJ3*uDg+(^}#zPH2kYKm$*x zU>ufnvuwU{>B?WZh??a|0}ZY$?n6%2f=&J#LTk#m)O^@r zsADqrrd_u9h}-HqTcjXSwLdJ@Oj}m0 zjjfQ#n+8;V&3IPRCT`H$dLAu8P*w`VHy{f(mu^drJH6_wcZ7o+!V58A+-S~Hu;%b{ zEAsh^+!ED1lK%|ldG6n4;CAWftaAbe87}e@RiGqp`#@C;@zWkgRl!CSnk@^m&I1MR zEI5|NzS}M5ujQWkXs0@3TO%1an(gNXBnVkccsq-acl)uoXGnBwEk#s@lErB-W4|j?gbhrImszw+fXC z1ruLZ2O2j|8(?=9j4yN69Aw)`Bm8P#K_t!u-MrOF<_emm-RuMPKSxs534&t%F~xbl z3@AA}?i_b!%0az~T)$kv_Y3~fj`vx*;YTCrCEWx0{m~xlv2!xgZ|8+Xdta&%0J7rK z?KjolY%d$t1F2)ajd?Z<@lP6z=1mGdub2EYI*N|JsofT};-@Qt8k&);Dn@Xh<0qzd z9x!-4tKa(lSI$EY-(rsP%<13qao-#y1Gn~-;-gO!Mew+|=H&n>F@A6g3&U-I3j)z# z|8g4-#aVYz7m>R*Xf$sgzUPblAiQYnOiZ*ev!R}Vny|Jdy1f8zN_EmBRVV1~pC-7> zY&1rc%kR^3x`Uk4sF*HE2sF*s&BsMUhHABZf&cpxp<>^0YI{7bf46^yoEW5FMXz8) zL+U@C>x1>{T|GP^KxcCg!hqciNch7h;NpLKw|}Z1T+h8@vZBxP_CsC|ms`&{9nh~8 zM35^OF{^*R60Z<u9o}3reM@RT)GyTj;I}%0T{uZ}RP; zmhFmg%Lmmp#K^0qUW}TWYS1Tk{$x_?Os16~LgLp-7~|d6Z)P_QPCq$)O3~sl5WSK) zLkLw2n7o)%`~yRk_P+p;Bw12ync0xIJIII7vt9JAn$g=fPK&=ndr1qyY$;a~XRh(L zW3CCMA^!FFUWvhDm#=sBuNaaP)v6WU#En2ri!7ye$I&KCTF*8RnriS$l)k$I!;(#{%7^2p^d z#j3R^E-iosKnS8<+$kLD0(ZpQ?2Ts8^W?ln%1Z&W;DYbxDY+6{s~S~xpNxs<RsY42?i51(0XwtHAU8%(5T)@GNCPdW$B>^ZF6(43@?;ip``W*qQxjR?u6=*ir za}Tlq+;^j|nyOzeeyM;;&?@aj-pH*jF#$kUa8#^*=h~f~>YlUm$Ya%Wt6yYUS#WJnyv9u}$}_ zN`9U0i8!Gfn8gA#`>jp}p<)hv*?HCpIFTfkK-lwE(l|!^J2E2u_JXA<6k1wJX=rS`53zBt zfggiNKOV=R0M5RXUqA!XCiMTAb%Z4q$W2gjZL$CK(tYmI`pqG>cQG;0TvW3Ws_lbK z)4C?Z8-zNVa=V1nhU7%9rP@!niAFDv=mh9K=0*vlBjlpQIV{;YTRv+AOoOOxG?zoC z6@P~_oK1g69Oi~C0ft#Uvrx0qr-(oicOAU<0~R~ME7ZGhm?*NLb8fb33$W=tT5{fp zc{XPo$}X0)E1nvaO@TkO>}jVj3A*T&JQ7u%3&*4ng&C>pu_X@hH*cFe8@0Z$@M2$_ zT;FWz*QRtXMdct62M!*X1;Mg1#Z}MB($v(*bPQ-6Cg#D098X+I^<6iTWqY>2*4{S=$p z9Y7^G9BJxGW6OdySh;Bx{X7PiaPc!>Q)IniF0yX10|7tZ1VdyJQr9#5;VV<{rxGbjeb?7 zCfymP<%%75K%#01Fc~- zkPNRy7frs3KmG;gbp+t8)(vv+uLJc~(C_4Sc3cRK4z&(H6KapOzp@X-YTCo81wa|- zVs(EmI(=F+XnEPg-bg};2q*LRlULV~TQ=U8o4FY!aEp z+i{=uwA%~E7%S*y@VrIvIB4=Rg8_==v#i} zsJqJa!y)r;-*LDBa`{H+QvnbU_kDR(Ep1_G9!Sm|H_R4|vgp_7z%UWAdi=&^+w`W)v^pYv?TrkEh3bP7J7O37ysF}Mo?LmNT za0x=A+m;Lqug&q}(W*c)wRc>5^~Dq}LD)TV|Ee;(_%vja9>>PE;|IIv7w_8Hd+B}W z*hNr(dfh~GbilWN*7tsPUH@^{2L}k4eF#8*e>V9z3pQPSTws0E_}`LGz{JDD;}a2i zZ>jGJ{s?+|`TO^8YhmCuUNCzQJxI@$M1uu}nkIpusG`*b8Q+ znpKR!msY&kP~`)F4_w+8EtVhp<63>D%@GTd)bP>mSN8HWF8=6bM&ZAqD~bE*O%Zas zX&zDjScw_H!HwcZBn#OF>|S;}J}8=A~XA;ovFuO^vaa7~33 z?IUD7z`JF_`HQgxi4DArHgojl@QW;ln?z_5)0B#~HUZ;%QWnS*(mdiNm*+AesSE1Yo`- zA#e78${O|N6D#FqQ01H=gae}(y~iiUF=u$~JFFbve&1ROk7;?lCj6BK>NB<%drEfy zQPgdbu#Il>`hs(hkCr$|h>;tz+6j~)8wvMSU9|HWIj1F5Ty(7@>V`X|ePkLt=)}s| z2&)92%N73z8un8^VV~{808?qVh%7RkbhuyJfrC3BDzQHQb1BBv1EOd~4S|gzGW&sR z{3gQwV5et)1Eg~>*|kTixg4OsCUdw56SCSWq&QW_X$~#=y_?Z5JWpyHJ$wf(w|`Kq zDBm>rbbiMg`cP(I?>c5AU)b3D?6aycpZNP7<+(^S+s+LlIxlX^Y_jbv%>GHLQ}l*> z4e`=MGc(3`dU`H~G0fCorV)N+3NC`4GG6YyA)lHW=^|?)OcqE4#l+%;FnRVRI1okh zrkzmW^L9Y!+al5CGpdWp?H?3`*qo52i&k+W|wQ4?ZTrtY3zFF;Avclow6EHd(9uEB5Y_Y zY$QBkBs`))b*=Zu$l)1bZK10zh(ky9!u4qs2d(Y%U}$V-0-{>6tUQo{prn$8B6rQT z)x1x45^*wXaDM;9!KxH6JgV0ZfXVuqYD$G+Ii zCf61c>7;zx@!{Z>;q#$++>wd8iKpNalOG)qAsDFDDUKcBcDOeS|0oh9(vQ*M!uspb zaf#)N8DhBhbycEVKlCR4*4?0()1PLW0I+d}&}?loX9N)@)nFoOgE7OmIV zQ=IFIovp-Go}76~(k{N3v&3_r8EUN|kGr*G?^!Ssw4e%uC=h(3mkA^;vEO&)>WxB1}Lmim|f zt^xgiJwdUBPl7v7DzE#j?-U~UjmdkWuhAbNtWV!qeSd*JmQ>%c(cr%y{^tt3rxp$V zpWN-0u;8PGkgmJ@kG-@bCrrQ=V~-+y648GAqaNpmAbK?jQo@ zf{6(G>{{Y9X;C#-egtwj~F-vT|-hN7l@0kzv4Y#VD@mZ6z< zi>>#%KxnHw{DtjlAZj$Mx15~fpzju+xYH0%2~tKZykV6V8n5*Y!xvq_NC23*DE51? zqV)-RMI~&X>NxSSW;<2HZ(@pl`RI1ER)18~VIva^4j4x~&U^1KWh!j76@zg9f~M1q zz1|)T2ZQn=O0n0~H9{q;L%F-Yeh1)t>#M<4)1=)RFRk{9`9%+f14Virc8zUapQ((9 zit=3#RJue4YbGU|t@g){OQe}`_F#}OP-JR82Q3$h!Nqyq#(5P{sm9I8a}&kkd2zr* zPAL>k+|++`@h(%Sc$>Jqm<{Yll2p0lC+7;F8!^z)747ucj(LRrvDRLffyz;IGVQp< z*EPgiW^K<-;X064jFUN2`&`9y@f5P@IlfKlsW#%QjNsY(95}eI)Zk#WoIuAwm|;-m zz+L5ibNU3!o8GCLIZ9dJfu9`XVS3F_Dolj&W!8rChXGv(;!>j4nn`uiAUCG!e4(JY zEojJmEU~E1h^)|(V$1l@fUdTZnl=Iep;(JIfBG&I+N<^gm_ObMYYrgB8U+5R1kJG;uE z6B2BQ&7ov~765H=le%9HLH~k!O1V?g=4;oeRPqmb^`am(WI%v-yJ{|+$#>X#)RSY> zzrIx@XO7D|G)$$!_QZ~1bm@}f8eq_Zk}f^hTFUf%1CFC&`Ibb4EIk|Kaaf|K!Wy(V z!6=+z;1!Dyb)nz-e_DpgduhP+M_cm5w>jS4XR?U#XvI%Hx!%f$>VR=WP8b6QvGTo5 z%Y#crm!Yeko85_<&o2Gnn8+zfams{Eh@#}L8foehZRQyekYN??Drd#kZi32_a+u+K zd3WyP2>WH&WF7y}%Sz1Z1j#MZ@A`BYxF%T9x(O)9W7Inyn=bDF{wb*yY2t~_g zO#F4eAt6VkO5->b{W7)sqEdgCO@*6~1tPeTygr_FUI&*%28mAt=;&S1N<8bZYj#vAE)K;f<>(@E{dOo9Q z)@<%Yni>k+P&&{~wnrCi?mLC)>gu%t9SvSn%3LHwfo|su8NUc;E?en@=CM;Xs|-a; zwX-AwmQnE4(-JqhHTX=}$p`sLVNZJ8U2c9HH;{AV)ntL*%pI<- zounwZPjA%a&%zT-Pf%*{R3lm!UuTe?N=E}L2HE2!mxy;ajD;!ngc;k(pOK8N`@x=ys9o#|=&laMYxi}uS>qa_WkY+oc18u-+|0Ny zGdFbDzAh}ef>6i8_Iy48Cle(vA;3H`knm`0DQEw;PJriZzUK#ZmB34u!}TZmi{|gl zH*vuW)zX_>+EHx=6pVm z2YQDrw|_W4<9^AZUs}oLt8mA)>tBdZ`?Jcchf1O}@G%d`!HSt7)2?sf(oCAfPJDEZ z`)7fI%eavwU%QgLE>3M8Ud6G4t;}zZOjJ?24Xe!d)#-@d+TE`&>IR=&zkkvF%e6XB zJvXe6DId?~DUSM;11nLHC-W?THKUX{E+Gd@Aib);%<7_+%V)A0iC8)kIp*_+J!3ox%6 z4w#4PT~hJj!{&OSH=}uujP)%Kefs;xNG$)u#>&W(5mxs!a&ho`vC2OJU9FFtFZ&0HiS;QIX;llx>o2UEZ4Lnx()*Ouc@mKVX_Wx<~6W4%zbcJ?lPh)V~>Yg9E`s z|N9g?4v~)jFU}^LDp?id!HZjj z(v+R_36x%LJDav5I~>)5fz#>GHe^xVTqya@y=*~sm!G=Jl&lg`I*7_$(|mEM zjErnIoF}w7z(9j;yTJ5fJ|1Cbz!PLFYxXJX5sQp0Icep#u55UOW|}FfMzu+h4K;Vm z=@w`XWe_t^;uGsj7N~#KN?^Yxa(#?z7N5X%lTS7__Pez!0|0RKs#W6SUqB}aQ{#f)wL5^2#ajqxXVV* zMwHMOa~8j^l`JGOiFdz$Q#4g$gs*;G#KJov!S%=_h<~wQb{obCEb>lnviOb*)lq6L z2o@C0jU`@}PhY-hyXxU`bgV>M*t%k-|TurFZw>ka_ zCZo=-?mJCZ)pT=sN{xYnbTGCN_&eJX|4M*}wHmN+619XH0;hDjLcz2#fv#f4)c@L+6-8>`ZxQ~{YDONdyoQFgw+WQXXjjbaB2TnUMT@PLP?%I9AOQHSBDxR*> zFsG^Q_@#l|TUqr3An6gA0}e74p|V>kgO0Gh7>d9~O%p#xDcc2-%vYrYgSmVY*7Wrt z>Z+m+C2fm-u$z(d^v`2=y;iySkd}Y=t3eEYr<+1~8a-WI082$hiSQ=fd;t7K!L5Ev zW&p^El>dVayIu2-F7y3G)ytm0?ri_2?<4Vr!eUc#-`n8wpg$UR&v|l&dCPI9JhCeH zji$K4H|XX7km*whZeCE)*#JaY9WOYx(1$Iv3V-*KG;67eXo$b+!hDfUdJ@8#Gfb}z zTsTL%3ftYUL#&$S+q8cqIC{U85c!D{wnbhl$Ox&MRPUAzpjs8K5{|!$j<|-TH4J}? z@G(Lw?sXdjuIYvzuu1Pq8D7vmH0e&$cVB+-pk}8F@sO5L95uz|6PgI~_S1!VeW^yZ z+^P@t3sx>AW4RE_JoPkz&c&~C$9k3_V!AVAW6oRACF;hbz2H4q<}I62ZVK*WdG^O9 zekmq>CVy@1yI&33sb~LK|F39FC-NRI8DiN(5xvF|4Q2g+v}Gi$20wJ|B!XXh!7nYM z?lXJ-eGmTE7d!745cgaFWU~`&DHQOC(dN7ZC-$Y42>6ic{ObJi`vEX`8A+r8X*vY6 z6?oyVk{mnV*s>yhN5A3LYt%h)^8XPk<3cD#1gB^%FEAdewXAmY$5vh^jIzv7J3Nt7 z;22El{m+3_YaKKjaal;* z_r`E=RICGU^xI@sH3wISgM{!Ozj+Ge97{=<)=Uo$&hR&R*Dt5SH6kseM6G{>`8L9y zVw3H)A1gx(fUziU=E75`Nqxa(9p9Cvy1IhK`8J*KBb?TX;~k0u$EiAd=(z1fp6Y~= z>2pK&V$5wI;liwq$IE%#0|S?K!Hd@Q+m0ugIl~Nli$nP8gZnY#a1TjRKs-E(K@$$J zh(~_(f%N>im&W&!&7RgIGDS-{H*T&(&CXC#sa<3>shs}yi>^qUvGxtH(H&nm?EUA0 zFx>7*RZN48&6LzfTxJg0RN#W<*qxZ3O<3QlogiG1PjZtZq-AUUmV2+M5AI^-KkA>- z)tPTmIbFPij#;3eyf_^zcj}7NSOL9oe=8v4X=ZIM6QRoA6ox_0#S$~WvptvR7SO{92T5vszkn=LIX?rIZ~gDy*I@M40+WpPR| zK*g*Ywd}R+;s?pdicWW2e~mMU#{N$>?9%Pi1Yr__uE_gv3?%56cafSTu-!J|2&$S0 zus4!!x>78q`Mc??DDAfPT!5!DN@-7xBD-Wgo=CxAU}^|6RG086WO)(IOmXtZ;TwYG zuFG##p72PA+wp#Kz-N#y`%+G7BxHMZ=rh#C(e*MbS))b z1V2}$S|g@qm5B%%)C(*SoToCGw;;sjR%YYRge(lAAV68!D)bvXQ7uQZ_dLd;82fZL zGL&GQyZc}#@vIff9%$XU(@3d=EG1cqeJIbX+lcEtx+tw&@-;bz^GpA}@ASRUin+<@ zl5DT)pQ~idCtE1V`r%S1g_c#NhI{W8vQA3c-w%fVg(`-1xUcrb&J21#X6SEz6$=v4 z>sfmMi=!0F1E|A|Y^3cm%B=~hUH{G(p1ct}5s#tX8KSijFMPsJLe`l@!bO*pMH0Rc zd2`y}JGkmtNa-;M9I8AXr`ygY&+XEuUn6m4#*3Vy2FAVVSrkqDtJKwJ`S?1 zO5BVPRmPBb0V_y}=M33YNL2+;#>DTSPqe;ypb}pqM5Tr8HO5@AkvT#PfAl$$e+^{@ zI26?Q%KT=CPD7<#=J(N7V?c;y`sB!pBaG%GlQQp58lARqCuC( zL1?O?Z(KP)29AT@j}P*}0krRJ$1 ztQ~`k@doZ$8M24^OKF|sfBU> z@of#0ZWX5!3a*QNwPO_I0BV^0oF~CcD>cGRXD`l7CztmK#yIpKvCell;p$i<+aW8V z3$-T5lY{6gaXDOH}`IR|G(W!SiDV6*w7(`%5{ry8fE zF0B;T#Q=pe5sEDbYBfx})-!Ni$*vbS6~8ifI@73PkT)aVsIb)Q^$ZCE1IajK?x~Zu zh(Q<+mEj4jV`~AOGy(q8&7vLLp8-7&P8CM5%4Z}I43BA!u@-gPaQ)<7e08o>ULH;) z+_ULhHZEg!Hsw~gKdV6i)9xIVl0QR=tQEi0cMZjRd?{Uqe zd8nN=E}Zn};)9UJ(@MAb4=ZLNK8kdvGMyG5vEc}HC8ii}$}|MYcx=|Ia6}JRW|;26 z4on|qzD`cXIQD6AfZY}uE6k>d#_po&@8>DhI7Uv-uVTo_ihdgvz_~42LtkG}^EDq7 zStg2Sh~mm#=L(OFkC%O$wtb}3pv*axtjSK#vL&UjmY%sI%SX$NXuTj%C%9U=kN~O+ zep4yGWfJ07JfAF^FB;6K0wxd+mZjY;J`@mN2YCT&PV)aTo9 z{!efd8`hkaNQEk1ecCMAkb!1$fePELVEKvjpx2JjB0ZvITR7CE=`e>uS0{f5 zotIDhM<<#X>sFx(YvJpu`wFz7(WFJxZ#>w-Mnmqb^Lahk5;^P1TiJP=Z%Dv1A(~H4 zT7Tl73cjQoc|t3JhvNDr5Jj_CrZ%CcmzEUi?#_SiyCGsx<(rs3lYBy+C;OQJ*V&AZ zB(3yNewm&0J7q?4aT?0j>~a5g|37RJq`vech-)vnkLW4*Px33~EBNE(<30E`ye>(zh2QxmmiyX>vhWUYFK$y?n1;xX<4yw&m=+!ci2qOF~oF|VdsAR{$he_ zYAjV}s0)GzjBRkvHf^|M5gD<~HA3ADifqfe2TeFoDTtw@yu~`%%w)8xd4;V#Wie`g z7xtsHJtTP@dKg~nzFD23Q^PBpdNj)p7o9mNdGXmss*11Y@AlBDGbMevLTklL^bGr^ z3ISwTTHDZcG%l6QHk@P-Jb@|<@cj}C z$(cVJ7Vf1j`R8|KzeI1ODR@9qmKu~N$*pQxIE`e$>u>&HkUC1GJ&EKWIFIu)kFg7b zu*Rt!|5(%Oab>AJqT9 z(H;nT#iwJm272N@`kKvh7GwEumzA$DN{Q`$85Uu0Ihl+hNOebjXMOx*P8|~74sA;O zi7N!uzF$8br)pJOWe-dQn1ICLsBs>(AUKSbByT5Tlxdrc$1*mN14R{vqjIl)NV84g zdZ~D7MH1ZJU$?qWzKF3vcmNatATK4Z1>VOuQB~q!O<$H)D{?uFN*Q|Ynebpe&NFd! zl0nY0sI{3`o}qsh>pHU1fU-W;@0#sGR50vXsH<3LUl;oOvf%)t-@}#AIt+@h2_O4u zWWI$ZEk6F!;M!v`zp65v{LCHpL~^W<`%7F|HbsLXaN%}(lzVU3m2;kOzj}Ul91YI2 z;Gi67LyN8=kn|voQRuhbYUPF#P7(h3yufjlSd&|WqS=@cbCePke>}|h(X&;MN=b;` z982Q58pNJD`*Y@R_IQr|v69G9Btvf`#vMP`4qqXSlg%yETrlVIBmdZDEQqt?-g%_T z-mgYs8p+689;e|#guXU?ZY<2~fI(~P1j!onc+^n)LG!pK&BonE}G>I$y z^`&;GKtMI|-2Z}Q(nR#`~GO3=UUS0D?9{e)jS7E+R<56-$Y z)ApNP>><{jX!eFHK5TY}b=ATPKT;T<+_L%Xq%OyJ2OT4M2^$2aQ53+K*fzdVax1MI zDJ&7^kRHro42o{2k{-$xGp1+_eTI1jt;2L2dMbPVj+(9)3V%D+{(@<&ZRWr2qm^}E zmdDbHY$&aI`_Ev;B>RMez;7G3oen`zQ?>BO+n`MfYR$$2R%Nxkp!JKB3Qk%WB7k!EgY{DiiW`hhWoM183 zQ}tTVVB8q)Y8g_h%P})K_zAHiH|q)U4L8r%<0{&j|Kexg`^wDEwUaRh&QJq{=g>4( zwVD-|6*y<w-rL6irdcuPh2%YfYhZbgnKoKxv&l}FF%L{THumqTq5o~)uXCOyaKuMvLmr77#J!TVbUDr{ z%XV`<^kg{hUAOuiI8_saF_&MpH66;(8AI^qu!41GwhMl`5L5Z5fVDKZ<8WWT08b}V z(cO^_^_LAqmo6ztJn)`c1qhYcD=5W7a4)CJJrd&t`J!P95+-d9d*g*OF?{2pA2n63gAg1PmV!%{2-pp*ihe9bR^0H!YEW9MVFpajFUbF(a%PeUFAL9p@& zjh--O1x`g|+V0|37I>VSPGa4y!+R?6Yu5$O!{BvCO3U$Tl5?$ggqX2-hF(0uUU2)p zZPA>*JJ$&c2gKfpl`$F@DgE_9j@vb3f53c_YQaiElbe0D$H7o@y{nH}Z`-}Bi%vD& z#bbulPu1i&einGYzpz}k#^K+5?QS6siX>Zt&PSGhSg)GfN5`bY3}U@P9!z=@ucA?m zUPjJ)5SK2pEYtPn^C|nOy^7>kFR7XedgsE(AvyufRgoDuA;fzVxCDmQW`#!%weWh{ zz|pn^Uii6IiC!~wSG*V$lkKO#UMA5fs%NwUT~bS8tFS!qBK)E+V&ZutI(5-=_#%4h z8Lq4aJA$mqxV#VP;xdqLzLn_3zW}A7_a){E5eByh(6v6(lJZf?Vj)_(Ve4Y?Zf85y z&!D=w+d;{&D{v|l8rw+I1FBhz6g zm0x3Hsr8xI|5T;JISt+8?WtVdPxLt@Uor==^O;;#I|^>2i^esZf;0HH2h^IkU~z`aYS_lwswTpGA|gHKspkTw4T+eArD5 z`Sq|p(-pS9p}i3z!us)-yBfkjvHidNlLeXLO668$A}j?jxoyt&Maxkl;F#> zb@{uog0->!^vg-vTa^J2$(qv(drtaZvevCNwC^b@2d&q;ChFnwxjgauU0CFhNj5A5 zfd@)z`82sYG2%UAQP$%sA)^r1vMo!<5rY;c%g%9*i#FU2Uz*5NOzi><;ow8@|6N+<$PBblo^Nj}51Hr!Z{tF8tN zYl2>_niZUk6SDWK{CJIbfH4yM|)5z8SBdVhSuE|3p^Wpg=)l})6<_|1`9) zH*q-CDysChdZrEbn)=qSO7)lKv8WM7zo!E~1&^OxUZ@Ks@3joQ<35d!(nbM_3sYFF zYv}YJSd~YQwue`$W*OFaKtSC>tOg&s9XqT(2d_#*X~Rwfj5tN%W=tieRV^ zyF6F+c>WIn%|J50u{teK6)*H)Z`q0Ui$GM17H#~f&H^n(v_v`e-NO-XAK`|Gv~DUw z#FVTpSs0I$m)%ND`r^vhPTl5{1LCH^aO7F|D7kjWxnY&sX@h>(?!l-E=M(qV){7f~ z;gp|Y@dDR+E$VK8CT6VfC88Q4>K=6a*ZW#H;u_ShuO=69!Tq8=2img%i{~QM`&Eq1 z4XGj<#v_mMnD%k0YY+~hK5tvMVFxY9a{i~*A)ja$K2E}e5;NKh77BNdPDq&LeJY7p zbd{)9ilB*?Gp=Pq1PTj@i~EK;q3(ti^_OP}uFpssznG9*!ncVGplfw z2AGyO6Q8NwyIcrm7Xh3m$uUzPZVuOVOpe50yakMU69DxzH>K=SCg_(xuf=)W71b) z39?=^CQ?D4Y<|gk_IiK)v(&`MlIt)X%!`Lv?Wfo|PYtSSHod~FTcbspiU4pb{>9Hu z&+vryqM)kuTgP@bTpv+Jfp`Zu#0uNBV#3@Oib)@nkm3scr-iRG5h}YU^ZA9s;H=rv zQie*)QkBC+=TCtJ+kAdury_l-dp5VRVgQOtK`=UiiTW5se{OqK(H=IR5~@vB72KIU zD}z(kxuVz0-ckH3TgO8w2&)FAaW8tdZi1$20P6r`MOjoK!cU{*!mgjr8K>{#Cz~wj z{W9S@TC@3@c)H#^dMCKLDN0M4*(xo3RRpi-hC{BDg&g?)RS{nkFd{QBB_^8e#igri zfndGE}DR!&H){yJoY7lyZ@~4g+SQ&GjcT#9QXr26` z1(LZqmUUlq10V>BFli0@tm|?Tk&^-heNQWhnRpakAnaLAU1y#b1>y)Vu4>c@ozE?O z+$HKgGK!5B*>dX@5#x{+ESOOBn}y=>m}f#Wb5|%LYGOfE`w|3h;2Woz&wL4>SG)>` zne&A~ijBS@o(Ux9#avL(*8+_jSfH#4w-W%aqAiRzQOtp123apHVb7^S73FF#U$kB@ z&09W;QlZPawdbv8v?=&&5@|?^`uif)4t2hUssNl76RhLv9CD{LEZxs?P(e+lMWt3M zioy1gX3Nh(M3h3`RyFuUd-K8DlKh>s2H{)i!!iH7CZP11(10(8zUIICIsgY_+!o-k&E&6vVh0By|TldcR%i8sp zlz=ETF}!BqlBt4Tf}>LLn3&5b+*V2f1}1_sW;Dvvb_aHh%vU(K?9RqcRaM7QzYjU8 zdaX!HBsb%;zGTSkJBP_{-7IC?n0Ox@NpD36lQv~pv$Lw*R7DF=O>igxP$VFMRGaaUZ5YDK~zWloh}g3~GUsIzfBp;Q9!^ zJJkCiF>B{mxAY9S{m9RjG7!8f&r`+NRQx3Yu1`oyhrzL6;K1OgDkxhZrq5}*Km5~d z3)+i>@WK`HdV$h;HZ3BJM-3#0>U%CJBd!$2ydVeK z^|`tj03PA8a9z1+Jy$wJnh*sg&?YM_e7)yRxto#-+&)6QgC7Hf;ULu}4TXtd(uBbG zS=HhB-*MqJnH6LQ^{^&H)Ab3%XPej`Jmb2)#f#RqCGKVsX!9>M6Cb?tF?HJ`OrF7fEizbyQ#2zMQYCz` z&%;2zcq(p(eXdEjlma(2h-**!MQaG30v8<<*!r1KJEP;qSEmT$JR6NC95RL@CQ$}6 zuJBhW*Hq;5u}6EE(4LL-k?sWJW=a4$$9WgF6V0Xg$(qqdT+(Yj2i?*FFm9+_;0M$~ zZ(KT6oM+cAds2c#(Mq{>@cX3j^M=XsK0;zZT6*jr@n{xK`Tto9ZY+M3qUzZDgyzbU zNP3&IOAIu^guJ^*5Ut>ZKG$xeArC^%Oq6y*wO|Z~w(bGGPlSd0>0X%?7^?TS6|Gl656P>Az06hL#LfT!wZQIf?9yKK z<0dh`88_nLK_maYHA4G7t(_vf^Qdc{d8GvWq zAaw$WM{XDOU|WodXI}>3rYG6fOW_?$JFgo>OgUw0X5qGU*ba5+rZ&xAYL^(qWf?_1c8HCVJFg70~~ z1nW$7=$?xe!q4t{fyAMH{Gw^4LpNKeU+yuAJMGH+0#v>0&1>J*K z=UrX~dQo={k{hn2!&sk56(>~TLQzsDz2PVHhIPqUaN*}$KG$P7ZGdA>8@SfIcy;a; z3WDXvAzY1>%V^y#vrB3&N3MgIv3%+ha1LpyHdBp5dpRO|CMe_D5`HF??PaQng|JJU z=Rx?nlz-Y@X}29yaxnLePA#qZ;!^Z?fOe}$8(oLFAs4v_2wzt{4NF>vV_!SrrbppM z?e0Y&93pb(Fs>Y$EsJn|7m=+ax)4n&9L5dzpW)b}xpY_w&^{a>hlKWOfZSanbxr+j z2Gs>n;kGWa6K!2eetAK-8W9Sxc%dLI1LD#n95Rz$-5)&ojQmj0UPSuWFC2D{I27^l z`;676b|}H&@W`Sj1^ZhbvGcV{=Mv$%Vb66k9tHS@*R?L@>REOQhf{v0_A(QWtlQhT znJn;3M6qp{REKRu?mW^Fz2ceFG)$mk!RDzEVV4jt4oIsOx%236HT7%~?XaJIbdS{e z>JLtjaHDbn?Rmtw35cDqs0hg>5?0VYIPhEw4tdG_y*-Z=##{u*i%|DB02LV#H@<4K zj7OfLfla6A8dM}edzCR@i5=|?Gp~mdj+d|5vk)dcVj|xK5+s|H}hbEuX zzq2Dahob8DRDQW6>wxj!4H92r-OeK~sl?qp-1FbtFiS==N>cc|LAKqLI9p{JslXtT zk}|TVc$#(oYVvK*Ax(#+eHZHmmPLMvyJR38+=_M@P>lmhu4HQ1e8^ac+}P;%D#*F(wk>C?>%auW(b0D zMWMcNBbAH0cwtK1yR(dDm#YVFRY%v)WS!AE-(>oHrUSrYOws@+6E#uF)U{7qkcrTa zx~rT`2x_7OQ9;3|a8?UCqv{RBxqrCM5A9@#sqpGE%?lzIe4mu!!6KPK*NrD{KQCU_ zM22#g&3Ab=VkVuW2Ahsr4#+4;VbvA(sC?LDMY_t%s9irl5bg^p?EG5ybIqfDT=PDK zg9*uHMLuN65DAT41dJzb?f&I3&0(T-N)0OcLHOCsquvq&OF~?t@3wKgMU(NYeCBaQ z@w%`p@an~G&ymlCe_T|r_N!bADF*2_F-eMiP4^-P0Rod$w@nD!RPPxJoD{n2kDWrh zF%ue`1n7#Vu7;#klbnj^Q2sTapZ>pXrGi>Om^Kn1bphi#VB9#2%W19o(U38qAM{0! z^vFszHVC6`&JXNZFW4Ea+9TQ(71fl;kV?()V@52j%9zliWE0urwZnn;EVbk%?;o`y z57phfhrsGSm9C`#aUEFH=!6C0mYwd^b1Ib8=PJ(%qTA5_Di zA)11qKMhD~J>Ook3og-gQ~0Ndzzc}hDtg8RL2^X4u*l=;zHj%b2voNKK+APziM1tt zNzWH=jwO9TQjG^<+;_#l`9wWK@{oxGj|lO#rYPKG%P+=VU7P>}=~=Pr4qH zIwlCPdn9nJdA_%ce8$;xJ?FrG?_Thnms?K!+U`OUZ)udp!}i^-kGaO}|^I~?w4K(#OMhXS){F^dv^ z$Q1e74Hdqemkkw4t(u+57t5UrNtr^d21^oi?M5)@_G+6J5l`6-^fk%XZng)|u;N^~ z;Fu2k)cI(!DqTHNqk;4_ffl=0Gbp`yFe#rMoCZq-NI|eJkSWwwj4c91T?F+oCwG@g zX*i@xGa#gyk-qV*0Vd?(tmpU5na|ihOW^O6#@Awtj0t%WFr2g+NNQ5<86>S<;IAHT z`IB^9eHe2tfC2Pe?O`=Kb(1OKD zOEI`15)I)U(osWrb=m0}LZcZbM=){L4WBd-PLfR@E0iYn4h4C1OTl+8c; zJh}B1HtQnM4Pl$A8vXte4PXN>sw=^`6okH@xyrTplUq6wNFNbzuMyV)`#WBf4v0tP0+u1>d~7jvdp*1Eu23og)quICDc=5nb)sKzD>L zDD5dhc0CY0{Hm?6^xbRMD2_>|IS0&#A&USe^(K~Ook^Y>3g;IlJo`tOw6+&opeU2$ zLD;8y|IF=y?iMUS$F=94q6u$44%pwJ8$vh~wD-hC&r=fsrBne&7YjnK1)Tv3lV^M~ZamID*HIjFV4+D8om*&|$HJK3 z7p$*<<$WsAw+{}8o0fE;)@gAh*FxNITHr>(@;OC8bwm+b!6h8{+U`;+Ehsl!tK-^f zfk5YgB0k!4o@Yl-4pZSK@&3nUP*l`}>M33rtBe_bJ5J)SdM@k$%B4k&uSpZo$l$}ErlxjTEB22ta zXvMk7Rq%!|RpkvD^xeG(3Ye&NKCT1O!Xa)v)ofEidocoIhKYDdxz3Rqj{^D=kN%eO z9A`pe5*ZveTS9OpPr_cQ)9$XqV=chSs}^oIAe^70G=as3m9{SOL|3(nwn3+313){V z?8Iniq@TJ0RV~#5y$DE=>2TGcMUn-c3|Otgog4DTO&z+5O+l;YQ4@yUs09ZH*H2aT zq9_LAySqLiTrv?)M++4bOORew>YZZ&qVaX!xcyj*Bli4<6L!S2=krf3A)5~#2^Bud z#GCzv_tsSp=OJT*L7swKq@UeY+vKFhzPWo1&gzU?%6BE z;{~#IO-BR_8&?y~{oNMhib-t|LD&P$RjgDDF*!abea2%!YNfzRb!_jX28VXx z9rY~6HNWHHK~gcbg2U}bivZSCm^$uOfO8|NBg42trBGbFB_nSl!YU&C{}x!>8z&7B z+k3_gzl#`dx5&Za&VR|sji`$Vs&-;{Vc!$GXQUHpgV*FUpohK}xA1iXukQi=k zkUGKs(WavL!k&9V5umxu@Rx*nls3SnW-6wy8|)r!v3tyGu?IN*!~w%G_npuaRnk5f z014_&G9eo*?va=)74T-fddE#-elu>yD{xdrXcZ3&dsL{VB#P@K=Mh_1Ieg^9dC0m& z7?Z+MO=xWDDoFITDsIZ@RX8kbw?~*1&xM)Hx+*OlT*>P9oD`0nr$k2u$gC1CnLgL0 zw{93vMUT87t_lD*1uYF>(3boaQ6=7-A^pg%xJXS(i`RfvN)R?)Fqo(jnqzzL6U2cBmw=2LtF`R$Ka|x zb6CDW*t$VWZLabrTR{ngLFXBy9h^(_q;-&%iC1%e&;(Ydjzi0!7OF^Itk6_|5||w2 z)>l4zy{FC+4WV{{XYj)UfZl)Q+9QKS4yA4sr%AbL005>dKvjGb5p;c=I{ZnWVZk&9 z>-u$5r+eAVexU0vWfT}cah9|jl+peGQ=o4u@C|LgBo^dN$AG-^Domxy*1A^BLXnW% z>3MN&l$z)Rij>d}v8jqXoy#mN#6s=(Xh+TUiDG-+=>mt+F!(;cpSo}DRfgZ^ z>+1m8fqRkiyB`YVf-mwTD%!_H{mQg7sZu`|WQ+>;Rg{4y zKt1bie_#RADH_5MGB)OXUc0s%3%W~o=i-v@)n3wb-t`GrZ(QT*agU47PlWXDfyMJg zM~$1HoNw-fcCTC_5@CE~1Av|Uxb(GS>|#=l3awNWhjOffSDj$Y#y93Y4ts%%${pWi z47a#1?p_lV^+4#a8(Abas=@9t7VdJeB8k*}$<*QPwU#)=wMV+uR1J-;L7F!0={fajq5WR_`fEM}=So6|r|$_bt3Yf|g#TBb7q&)1~t;Dq|K0A3nji`kM2 zx(iKkTcE$)A?(7mHvo_^=^l^DZ%?XR4j~%Hgi1}E>~PDWJ10uO4;fMv)uEIPik~Ue zU#VY*6NjedJ+E#SF%x}*f`my=11R-O%t0`&=p{d2H_p%rvqA?(Z3GA)-qq(3SB__i zY8aRzdwW^X9a5#O+1W$)5nB|%{t<`a2q?D?z`+BbS|aq^+xxpM%&mkSaoRhUz<;wM zb2yZmL{l-opv0-84e&l?&jNGIL>shc1zt5n>`byaYFrBZXb6Q;H3f>3Yw<-b{;5_< z>d5o=qLeQcA|=w`I=aXer9PM|M5UfhRF#|Y>K!+U`OUZ)ufS2ft6Wc)ii*pm%A1oR z1D&r>_9BF~rKJPVz+d!w9jVI000U0z7?ZaPm@N*2P63c$7HLH}ic+Y+>!L$i^3bHR zbDWgk)z>?B>gzgcP?p#g2Y8)vN$#5oR}m6dPzI^pA_sn7c)_>|RN?Itq*qvR6OdQ! zHES^#$I=O5#Ref3RG}Pyz?4WSUqy zwu_qdj|Fi_zAZbS40y+lU^wA3T0Sf|`PhKwya!4_Jemw$&Duwl3Si%}c&Wjx{d;QJ zT`Z2=zUCaYdtDUvn>vrG8o$#-Q0FL$gER$Mzc(+eTzx4OHYhr;O@n|cxLU*r4#=hQ zhb0!|&haz5S=YQ2A|{G<^9)9>!hZm?i^?D{d6QJflu)1`Et^{4GETjWT6FSLL1S)L zR-CI`^x~*Fz&(M%Z?n~Bbh5yB?Ahh*2wQK@6K$DN0YH?CsWVF{NG2|qf#zaVF29?+ zuN|ooi1U*FaQZyIS2H*qsbJKXJz|m9oQh<^y(bpo#nBaSXAK8)geMS@Mdt6*oQ9R^fE7BvB>KRYY zyG$zV87zKfXz_)P33Z(*+}B(TjPB5$XSC;<>}M7_n~MRG3of7V*uFmF@wYsWr&qVp z+-q?A*Xb!9S2oX4dD+#DYvVASEU>&cBJ4)OWZjeqP!x_8Rw)@MDySC7^OyAhXYbE? zB}tYvLF^M<%-qiw%gxMNTTgY*ki!SQ5+J}AKJlOPZ3u!OhwMRbsHN-HT{2@k=eWC> zsjBed6Hzsf%zLYM4dPn<7$fcmh8FwDr0%$i9uHiXRtl54N@ut^B6kK$gi7v z7=joqpcf1{u#RBJInDr+7-*&`V1jclzDL~&Ut4MUwY(V`AT zAh^6wNOuwG6lvjB8lq8OT)CYAzXht10i0N3*lohj-*AlG*_w<7NE-K6jy_OFkheZD zIRK5AKckD-xh0!J^fdvf(vx3Ihy!KW(E@t%Y3QoJ5n|^0;evpo^fQ;Hh!X|!>O`7G z*r>$bQXsEB3ufL9%zOcI8CPB?iBuuXq z+AGF;PnTiITC?%{i(FA07^DN`&Zch;h?m%@ZFP3H2|JG*nZyVidcxiNtj!jf3$Er_ zokKq>I5kE#Y7fNC6QQ=Y7ADT6HmJF!c#;OYIdp5k+;$7hZ|&B8ZmkQ9@W1KAfG>Vo z$^91e&ACNfWmwB0pk~4Rdv4-!X}G*kD0jQnUImAbrpDU#Ui2gUJY#ql?1T)sPEyJxmME&vpG`yUrb zX;|M*ov*pRov_^poWBV;{?L$LBHHwXuvEm;Mpe@!!+yr#=4eCQhlg3KT&BUN52uZ` zUWa4{ey{rN#c;^+@4=LDAT`l@72u&gY?eGfu}|`4MSD2#0Pwnw3X;LJo!{??162jY zVD^=KHAF!@By5kF)vQnF&MDVz<5f z=SsEJc=#R^&0iG9?;EB+yh0-t{ll`Ww7NK%+Xn^U`29-Wxd3`hRQWyztPc_EgW&MV zxQ55vgCS35#HEfPHS;hWFNJ|)jve*~*a0?pLW(UvS6U{WHbTmE1m$gtz4EKk5&&C8 zu%v~Q*17KG;Q;rguXhw5B*cEe@C876saSt?#P$%8Un*2tv1bKsm(>AA)!Cbg#&z#^ zOKNO~1FJ-L0r&rKMmTSfi3;2*!15+S8V{H2J*zcdVahKBVPk?Q93!waNE1w-O80km zl#3@STITbqQ=qHE=N0L_xBgt(A)y^ImiH5+X|I@VcLB>ASDOZ=&&li- zISxdDaA%cYqdGKKMfa*!WU^@baKZV{@1O@0rgLoyOUelVJtVX_;qvWdmX&5hXI4l| zpzJemf^;rj8Qw)HHAiSuy#HTTJpFyd`Tz54+BN>$wdmcMtjKslHNn~i_Mmw|_Wml?z!6yd)+3`nmP$D)uOZ_4)rM>A}90o8MhO3TNz zDCfwgh->VLp!0Xxex|tp+ZUiUq$%P24RsHeH@ufT3#Km>VU-R?R;!*yQPW6Zkk~SR zK0RA51C~@?iE>z%MFdf5-xt2-o8Q_mv)#xHw{~kk=O$nU)S<(kS^bmm`6}gV z)f@lwbw>8;^Y(#+1?@ljzI{ghkF?=6jH^|~eb4uw=?C@hiN3#X`;5WamanRd{(WQ9 zys|v&7xeW#>mU8yKey>ut7rerrlzFx)f;w|<3H6pl)3-l>(9aXoc(?O=yR_BhAD=3 zI~)JG!8x5a@T2kJ?`h+6e(HO!S{py_O7vZk{im<@N9~V2mww;ZA2i^rdOb!RV*eA@ z{wJGr(RbIbU%%avpI_hCKj&-y#2oT@b2Y~HFLyzqKK^&FF|^Cq@AJcYpJ(;@`}OOw zq&`=5S1BK_9l~ONzAo5je?7l}ZVlx$lB>$)ADNe$8juy5cm3h>RL3=5 zUAFHf?h*e-?$56QDiBem&@jb{C<+O@Ca!b-oPJ{6avD+Z=Uu}2I#2x7T8`1T{Y9QQ z&_6!j{MzkVyOmx4V`Ja@^J3_cJx1a9N-QWMj`u$Vm^y|;+uTdL^<;QDCAD27y z3GerhT;Esy_{Xl(lTW1V$T(lb-8tjxhIV`UAG;UWGgBRjT~Bb>I(xnL{PeompT{jY z|HZdk#r)Q8?PuDq7VDo1GX7LEh^*+~VExhW_){$iv?;`3sifnH1?)fl=KXDf$?ohKknExoC_#>?!W-QS7XK}f{J{J{Ii;W&OVTrUEsBwGpe`>TJ{J2{WEJLu$A3)ioIX< z>(`GG8N1gu-q2NY2Oy{|Zpi{irpVp2IFkmp?H$d|wEK zA0;xL$yl!yr9_;zj2IfW8llaSLf#kFPu}0Ii{Z$nAMHJVWDUF;4<0aW!xB+<*Vo5$ z*j@PkcVCU~y(+d_Fz(mz76mQpRewY6*SpVC5r~gL+pB)G51KmvpK5))>F6KlV0Q)m z-D?%&8b*T6|LE0y^?Tm;^KR_-gpuvdKMDkYVr-6igfZv7x*yry3&hZTrdRQk2`(AW zfY;Tol2QBb@8dB7P%+;4pu_Fw>;5|T-!ZOrw=Q|%z-Un9fM0*-A8lW+cXr?0gTMOs zPxakCp?7PywrjV*{MK&m=h)nG$?VHqNDUsenx`=<16V+u%T z<3vxi9HL4p6_{HND942Cb~pAN4n4<%Lrzoa~Ah7QWGRRt(X943W(_-<$?_eo6+TkDbN%#31K}TyqIxwAcVObhW3OCmC-|OUB@FV8>Y`2+9@DEucV7aLA^_8Rmo33B$PWs zvH`+y)45WI!+7)cKm~tC2h?N2@^G**ZGv(p9vROC`E$YD-xSQBo=^|M^(hca8#Y>K zoqy#JY2f&u6LkV!0TsphyNt=a!oyM#jGxih0^w(=2$}{=pDU)%7(ttHaa-c|l%t?L zDAK>b$Cq}Gj}!YaDX=~Pp+w|QFrhwRdkD}pAs^n8ZnQK!{A01TNBAs-ju22%fcEI0 zxHiO9QH}xIouJ$a9)9D3ou<8EwwDNs)~Ex3IY64(#BB}nv>|MSUHfxBeHRc`;LYD` z*d8LbqhNay)C_0_wg(`+M(#&T!}0g42`vUlb+2(?dw1xxCh9pT%H0U!${|1|27E4N z>J|82od+;~G5B(=oXg1xAn3c2;= zKDr;B?>KE7ycW{vGDSjbU}Fg z9|~;>=W%V)faMLSmcP<^E-r(*aQIlUyp32UK|X6w5U&r^l~^AIXp`Fd-=+;$7hZ|&B8X3Z5~ zUGXzrHbOa7f$r;_P5Iim!M&R1-qR7$c+g>Om_KndsF{InI#q<#4gq)B_>O@-tCJi2 z3d)g(=6c}aG%Q2Onq0~-xR?HO^Ipy`ZHQh~bZeD5Q))I{7@ThRg5_OCybSvo7v}+n zO1NjlHPVtRnXOZ?K+d_H&I{}Oyd=Dg3ae(IXX*KRdtD9)LVFl*(ge*i-wyRwPk`8g ziIrs@=t61q6t{q;tGRl0O&K`FGa+wO^EO_;d&uu9USTQF5Ktc`v%(RiS6a1&tx?!3 z0^36}QNO`UBu7qp-&O(ez%(q1bfE(C_Er#z00=!%l3s_-fM~M*v~gijV{be#^UxSy z8IYnXLI|T8q@HL>y`t$qcN;2=f*=99xw0}3RK0>>l_ZWm>_nje63soSBwgX$$FT-e zaxOsdzV0_Lu0s(A&e^&-1Zmr~f(dTvuz3S@;6ipPk zf(0I^v`1n>$y9?69E(>_NTE4 zx#)-Hau>T-c8fdlKiFDo)?Hy^LZ!~=4h6j*L?}3BV>_N!glHm-6BCyjK|Z_%<@FeF zRasMv>SJrB`@l8IJ?Nd^?G{O19ZatkVU7rgY}yb3+e7N(K5iAQ1WeOF5*$7$%1nVq zjTGQ2b24A)g!x118WX-2xgb_wtM^q#f!&wj<*z8%cK4gWKny@RSjAER4fL^Y$3!cy z6Gb%l%HFPgUT5-v>s`94g!XxCmD}mLB5aE1zse{_j`{in`?$^laS4b^LwemHC7@2z z6(z#m8^kKs>C*bTn@+4M*F)&zBdol4b+vF|A4(A2DK%FG^qauaPA#P6;reYm=N{w_Pxzp zYd~y@d^W9`izOfx2xfuicAFiQ1iyzgD%vjexU@dc;}%dwfW&@l8Q30yPzCLk>g?rC z@Q?qei2HvK9RI-glB3Rq5>A5rtPJcoMLkgHgw|_Ag9f&b``Wj@0m_}C9Te%6qOQfB zjoUPifo9ixVN%Dr_$>$@y zcyMZ6hzI~P?>mUGO5|pGWCdlt4@eQnite)tkSB;bDwbttAc{li-on8}kt`^onBAzj zw#@fP43HkZU{r~MABaGhrf;MbXb4>ackt4r9|-%wQZ3-yDucR1>XvG7pJn?PujB_^zb5VnRY zHWuxWEkGB4(k49+44WM;y~+@UHhOzVFE|cRX>qlmPe0<32SXxQB_1m%K4z8SF3={< z@fNcNiVg zOu&vJY>|nX-GSF1i5h$vQP3=zCQ7%1mMzem0??@5?mAz-4!UsD{+T(NMkAn|ashb7 zxc@(do+xXx2^SiYL_nYCdI((^dL%`5@cuRuKwoP?bO()TB<-l0uLJqh6zgN8_1&2X zKWP*Q^RagL{(|ixqZ}tdnV_vlB5>*=m_MQm6gB{mf!rA?=D3=pVu9=SwjusL;_i2b zLJF*E>P~EwP8SjR%VsEnF<#ux&>cZq9tl(pBbnq@T0I$98tRvpkc^_r^t$ z5|f#6v4o|F(POkHVx-Xj9AMnh9|nndk}WRFS`IU0Is_WANg&nQAu= z809XSVk)mq6Je!w4wju~C8F#ODjv8{Sa_3D*=*?=z|?xKn|;B7Ru9Jz6b zQZaulNap}3)rDJ@!EZDbUTKQs?=JkDIStt3E(mFd;nN)=mC)T40-#`TQm{AW2!CV70^IF4V$pf#H2LM}x z!0e3Xgf>Og1OGT&T8dKPep?Z$LK@u(NTUdSo|Z#|Cc*TjL8pN2aOmigeZb;yQH|0Q zHf;{jsEC&USvhy&d9z@dD!*-t*q$bAbHH{NAouM5{K`sQyr?NXyW%{@%=B^XUtMP+ zF180EAi_$>vls-p9TRPaESL^cK>m0^d|n{s&~1}o{SaO(u_S_aNa)Cf!e~dQ)RPtY znf<=Jp9xuBs1B_`(2j)gI>eKfM~dw+^)VSX&gIK{4xHl;gpsaq2q$;0xZ7^!FI2UT zPANHNoW9GnW;9DiU)OYpkZFgA1=h$g7%_?MZVL+B&3lkNF{6NDs zD#LlR4alz*bq-jb0+zR|42Lx$U06Y-(!BQdwxbI6KGOhNj!371Z~h-Ewx;+C9YBr@ZPd&Bk^%^4$i3WNq= zdrT+?!TMxLl}3f|9{dXTuY6Wa&lU3@E}eey^f$%E!B}IC=Zd(EaS8zW%ZhTBMld&X ze*pN|hmWNvQymQhFxjh?5cG;Vsa?CrB@C!l1obYX9Ep%q(XZ~ zM<&H{>2tq4OsL0^43nyzf+r==v0$xm9fQzzg^^qP#kN~uervb(Gi+kKvrrlX7hu4n z&Gsu)wF;#6)jX~Z@pZ-Vbu~C{LOaCa>6s|b6GY4wjaA-wT2bx5(|Kx@F!E7#HLi7* zUeRTB$2N82;k7w32tUyB#53;BN84Am;;K0QKyINQ)Z@}DFtbX_?3*G?`~_X?#sfgq zhOpz*IcytK7`8}OF<{juz&&pPewKTg4w$u9mIUaTZhO5|(HR`t;WduL04tgSZRX}3 z)`oZ~R^heGd_t!y@QphDbR}wq1oAJt{a6m2lNL6fu3M7voa`W{DPVh=aQc>kH-uUL zPLU(HdkcP$VF-!VE(kcz^|`aRjs16X~{3Ee^U$oeABIo}BrrZ#^gvZp+8%NNDaE zkUCI3M8??K=m?f6b&e=4z>Lme{@K$r0}oGV)F~jQfZ&PH$T7+F!Pcz{1D0wWaYrO+ z4k(Y))%EX{#GPW(GOMOuWn7dDEdU=S=G~YK=94X4zmDIxPC@YXHf&%e7wk9Es07>nfI|BkT|Jl=AAbzUxCU!a zZaB)L9TRZ$wbLq(5ZY(CeWlOS=!s!Lv(J%=-M-?q5=W6J@`-vG9WW&f%6P3-O|`yj z2D@)%P_xnnUE{&gVrcr6B_7wp{eB4r^e&D-)S&%*F0?(2hj4|K2wOv$(8ozwfzTSE z_m&)qTSGiC5!8;f)s(6T3aC+#f>pO$5|sOhw()zq9z=+}Dh}B5xmc3I_w~(?ad9Nz zoxb7lb)q3yv6gDIs2A-zHq!XBau=}ODKv5H&L7k`>w_kiU#k@pGWXTQ#Is+I3&DDD z9alBBt_NCys8p zvTU_vrEF$RXFPqkFQr`~c4MiL4rT%b|1443Tl@d(b_>jJ?bd!~%^}~N3%eB{Mj(Wd zZMDPFm0gOxS1udmbOCY#-rPf{z=JX{0-vS`0g#o4V&6nu{amb~;2x)avxpW*b$FNu zNQ1N3BCBreQ|!K_!3uW{v7=~FqX+BR0*Np-+)x$Opk#GIKV$;q-dkjaU84ormdNk} zvF6YZ9l^Y?VII|8_^LDjd|gZ9JJ^?Y&@d>qS1k6yIS)@T6annu7%TxI9a`_3x0uM7 zM1dlVfY$?Z>vu@&8+wniY}4PXV>@iW#n}194mEa8iX%VQZ|M%Pv^Dns9RUZ?7=AP*Y0*k|Tmc-kp2w6bFBPO;C@) zo?AdeW4yF0foL{fa;+V8;)gqpVI+4_fY#81RD@vu+g{D{%J7ExN|ZwMpkF~WOc==` zz$!D5eG|3{Sqt=-nE;!DLCRZ)sEaC4Djdbpe`W%NOm6UdMqutR3W2QjyhjRsT=gK! zpt*G-?=~)>i&*-&@_;TB2IXRha|Heg7PM*Nc&QV55~7cjQlWG1!8}nepm(_m#>K^g z93LMxH<+vtgRV;#dP@MZRhRXR(E@6-=STeuhuZ^ON7BX6JB10pIe3Wil% z8Ed8{U^`M&uO+Tu+Yz0{kj@Hd>)dzP(%}>dsR~u@H;zJ+Wh3G$NMG9pfHpt_=Szq1 zM}cmNsWiJc7$s!vYf_o;6Hi+2-309U#f^zz(hbJFx4EIzfck35_sTKMKtG_q8g!3i!2?(Po3-QC@x zgAaFR?#w*QTIcP&opt_I_3zsItGvjea8;$FSqA9mkl86gaXBXxw}jS`?gdD_c|iv@$n;K$zdg($L(3q{@u^^u+V!U+uF8<}0OL4T=VCEU__| zw=ia0$p2F=Z4B3BhA07A^QGMANB(ILibcMBGVwnMbCLgEe}tqW3Z!q%yhh)jM|&4C z3Gk5y8A;;;kQV;9`*Uawj-`a1jpi$&V2>N=oXNZJV6W)gSb@cUCM5LS z9NU>ujfFa;eg_EKCc|7hc`r;H(^Roaem~e=VLDf9=>dK>!CBy)f+yutVKc*zxbFLR z!2u7X$-AA;@;QXR@aMpQqT$%WA<$M5ysOuC=w7^d_4nC-l58<V|R$&VK75DVJ{aJPJTvdI-F&&q%_hTCLvp`C66R7 zEtzP7g~grCC#GiwughLOE1numJ4cHYE2NG*zH#in;LDXml&Z&ah{)bMO`ht}&|Hu# zJ+Lo_etO);hcRSHfco@e7BE>DO^{CTj+Bh?LQ+GMue!ehxRPf-xpWqflYV>%h*sDQ zg(0k&i&WV-dRx_z#6*$%#p9E>^td~`xEX$JWNO%pUM?k?v}7K}&YjZt_tDkxM`Y&r zN&|lb_?15gpm^xANB1jbMK;nw2UT-a;R16flvAt;ujJvlX)$w6c^R; z7S%5&Q;RXK`Lm%)N`?RKu^ZX{-7Ml{Lj@BX`HsAn6p-b`KP$?G`Kv0B%frz@M06@ zi@zBN)`oq~0^L?YPi#W1n)kf~Q{)hIFOHq&cbDWgcK>Jt9Dl<%wGnpl{pf5yrtF>* zVYzj=4rN(v!4&*&dAZ7!xP7^vyiSXrm6n(JBKVa}$F}zH#E@xTxsRr#D;`=_q7U(r zZRe5wQNWZoBmcW|*J#3|U}ca_390xw@f(XF(*b#7HiN^3QS~Rw#*mYRTq18(WSz|R zufvtfnaHLCt{qh z8(ZUq$V1T~G$+_W%u*DC9^psj;aw-ptNMS7Hwyu(q+2t%w;Ps7{cRm8sj1%+Cz%lR zh+Z+Z^!QtlobQ5VOhCwGI|>vj=cg2Y?*Rdod%tRxhD8wvHCctr?eY3asZwAbCp81> zIlpptFf=^Y+{Gv`ekmY-3IvSkamqmCn ze4i6DiPVwc#Ih>$Axx#+w*jUHHQdJ{_nyKOn0TjT$LmK`%xK8p6C*_^4q}PGJiS^; zG|c_(k*zx!&H($gPFt=0*mxXopqP>DCb$9GZHk5mY-96178~VQ#zHvDFxVZm@t%DWm`cJloC>ONT@`CFLR))sC zsy>H4Ntw5^Kob-IT_$qytp%<;Bc3B~7g=CE^#MBKbvx$6qR?_dBJ#`$Epj>4Vk`Uljqp@0(b$ro?|ux+$g`$-FnQD*BOJ>tCxZ&x*sFIdVM; zV>Q$;KnWB({=Fh?WT5@Fpxq|=tv>7>8K;-Lhx^|osH{$VPv@%6)x2%Xcp%1i7uscnB%`h}#eYH7h)s;*)=wP~oI_=wnA)Om@M^360K1zV>t$A6pDw z4lC497d1`iME9sMGY{Vpd2Bdv>RT~@xXjc%KxOh=?ue`2W)HFIhh>8J!*F331r+XY zInFk+$b4kg5qXLQVJ9Qz#G!jf=JfZORaTC!2L0!j1`2nEn(lG5zaKucd`A6KD9{fJ zp>~Ha7-jL)^k?(Qq$x}pQ<=!9@w;Vs@%n%nR{heSYMr~YjVAC=hnAN?izvvMU31wO zs!+Y(aPv#GzFLt+s?byeZ?ycre-8%J<=*%GL?#?SX2xCRln9Qs20JAOlp2dHITp7t z=k3rNZM2O|2=%;_8K!Fm`WKs#FD=?8hw3CVi_%~{<3qu%r;ydV6&WUAibv{H3y9`a zcZoaI-4>hi0CwgL%Ch^ir34$uT!ns2VdB?byJUQmJbDqzkGRmip*IBRB7#$9(!O2M zxr;q_PX>IK=vF0bj;7)sNZbqfkSlwF|^ER z`~CVx^3V~v4NVmL#xuQApC< z+a5(WHOLyn73b3&=+6JnpRb+P4g>#G+fu%wHiJ2RKYn7!mAxQ~<%G!F;Ca$jM= zwD(NDr6x;r9>dN{5!zBs&m$oQvYeXsFZelu20R29tx)!tGcHAR*#Qi00JfnaEGJwz zrF1_JDn-y;2I?oM6PUEOz&LWbUmTo$*TVFo1?QCcYpb91l5>WM17!zh!cjg8pp3Ry zgr}`|JMIU?EfUh^FiV@as2a&_g8L1R?_8 zct!<&MkMDG%FtK>RSKBg;ZfPZ?oSw5?3Rll>tO<}t&KgH`Q*?G>m;cm>n|gbu7|}A z-8U(p(|wT&D=JX)E8_5tr7YE%rdD*6ma4v62iR7Yo-2M)EaC3r=9wsK#sq$~=%f=X zxZPU)1&t%|M!DSZ^k(Dpg;r!3c+?sOGC8yBTpL>FZV@DA1OX}{5h`~pmANYerl#A) zzrg)I%n_HDp}|9IEx22JuMeO+qB`|SD!g?~Fn;*n(hPHjxS?@m z&z%9`7>(8g=D+M}T^SQj%v41Q*YEdWL^jJLBd@EyZ5VO9ZrG7r1yOqrBVU5I>1#Dk z5%as2l7yi}-1B(V%Rgv_u~D&rylEj{CRDo&R8bpu?LiMIn|RqJv*I9YenG29U+CPB zcj$IB#y#AqSj+iDO4BleUJq%RkfJ-O_JiRe9OZshLK+Mv((3lnR}hciO0iMEvbULn zIV_zEfupO0Inc5#&X7ha1t|tc3;9<}N3V^PO?c`W<((jKjzo~2cWwc_^3f}Fr6Zz* zZm}SukTItv5{2D#cc&I`% ztF>=kcMX1}$N)Jbbd-t&R1W9h^-unQdjYs+w_XGb5f!>f==90!0V%p{YJ(vY=!&7mh<5n@)=`2%plOyp3H7tKOXt#`J1-A>!5JSjlV(+`Lzg3pA7nwfQ zFJJPD%1C^A6+oM7j)`g$LlFrPg!&nXRHvwq`atA&ZpxucFJXWSS=C-yU5x}#4s{o5zNT&Jty3BSJEwI-sF5h4w7&y75D_orGS z;}^|@M@O)3ysSW3;~8Gcu{Az%d?m@H%umy6wIK?ptW2~0{h{*1`M&YN{7w9VLczZI zN%(a&`Z*vv%Vy1jniGCywY`t)rcw2z7CxDO7*pQ00=-Z}rZ^B9AbH=tjYK3}vG^OyQ^oYRbGz?Q2 zmASpeu;X<1VDfi4IuuDDT7cp|Z$TJHmsOfrs%Q?>#lA)^y>thelrehm4kD+q`E=s& z_)l{wmK2`!V;9=q=>&F402ibMyU__xKWC}yx^}m8ZH2vY9r{+ktszGjS@9SuUbg4q z9Q%aQ%!h+*c?5MQvW*0I3KN=il9{`W_NWmrnvLq-tbe76Nfw*6NFRz@N}%(}S;ijV zSC>#h39aFK52(?VS*#llggJutr)cosG*c}x$MhL6-^KOLJq{o^wL0#NwCXW!Htdcvz=MN=xPG`QH^s~)T{2eq6z8JQab+E*_YK9e7T2nkiFD=T1 z`xb#RmB>{{--A93F9nm5m!aypu7^HFeAgoLam*$&)l@_h5ManZlBl^)A@4$?!UEi?D)|FUu#rzV(yR60RvZbcF7kxBwNNA6S$+Rg?J5W`OfLEK`KljzVxqk zM{{l+5>|2Tm{mB-R0wr@I1=ocw;`2fhL5(g`s3cDq{bRay)~})TdJOB8kB^zfOH|U z9k9TwO-K^Hv|9_o1|QrMC30D{koa4CnIdM&8%)%eoLMd|Neo`0upELd;hq*s%~F}K z97x6e`fseSh{9lj*-{Y8N^o0p<;yRs6;3yPdmSiFeO~Q!hXnA`Egzv(L|US2nW$Je zWG|B|+$HDmkvc(imRsN?J6z%?<=(gIQ?$aPVI%`&0VWELBew*jtO_|r`;1aAf!h3Z z)3xm5^XH< zW&FMbJ}NC9LQ^)%=WVow}b)5b_9~+ksp=ztaMi(pUtfSyTcgd|?k% z#6{K1EBdx@HBHYvllB8|hV*&q&4~f}QcdvgFarZp+ix z3210FNKq>H3OsH6kd6S1uJSN#(oyku@Cd&ti@#QAPO%~ue$6el#0JQ#P!w|JAf$ByAYJBW0=AKNH}fBKv{uA# zIY*dMrkQ~{xYwb6#FHU!1yHkx-QDdB7jKv;mK;vq3_95?h|eQiMjkjFt{W1Q>J+%} z=E4d^eJ~(OgOb6oIZ(+<*qxPRDy}i(KC9a8`5RPIWW8x+|98fGxG)xrfO^*}szy*^ zQ3K3oCwAO4UERq%_C!I@7iWv{z1>N3Srz|17Wsn1YEl`G<&Og8Az$9>8J??B3ST>c zZEwv~3M1IkMYgQ@s1KVv(=u({*%&gz{Hg=Rf9O{=cuuwnf}erbhsGyeFBiC%5L=lV|1cmC@(UDo>QrY_YUnM_d+S~E72n6n=TM; zoRu_8ge=7`RvpNaR}bESboU*CM2N}%R7SQttm91${zfVj^)mnz`tyY5*h3chVa!BJ z`SWTbe@@I_P!n|}EfNd&e8YIDRK08}&sC1gRc9LZq7`eI&%>5TW5gsaez+v?DQY+V zQ9{kp^bMS}QiA{50)C~OLu=N0wBe-qw&O12j=O4js&FNNk%D^T+l$d#A0kojMib=g zQ&w(+1XF3Z`{Pnj!Y&q+1QTQ>(ww}DAbPG__|_bK*in}Ij8XGQEs?uYIjBaiLf~Ti zLc)@^GAUAhT%SBjH+U+?hmJx+!ZA}UdQBrNBqSle;p`Drz*o^ zGm%o@bbs!3R!m>*?|%POjYs8#6kJ*jH%CMnSJM~a_x8`%P1BpseEguSF`MPut9j81 z0MN*9&ZwySV(u(+UA28_`hBNG`{ zHaoPu>3&v(b!@8Y6pSQ8t}J)%B!ATh9qq_cSFl&H5l$d1?;NlzN*r1;n~KvNa{8)Y zzZxR&6pZ1o6Vzq;27SaF&?F2!Ds;R#Peox`-caeYl_SM&F9fzF!9O<=oZFm4H8Qlv zbOdAZMCRDZ^*r?NeSM_qAn)5SYNVWxv*hSqV}2S*}`^;v>R zOPo7upc%?)dD%XazO}xrVv*+{#e;8>Zf4Q2i>=A9tS--lg|iym2bpw-hXK8&PECh2 zJ&f9I=lK7vSYP@7Jg-gGO_7fuFDA<)5RHz}4%)PV^kb!N1a90aTh8BPM6z%^-XB98 zS19nciE5DyQN*Kl0$%@<^x=|$GOI`Om0EQ&gCv_yn(_5tT(7(;qq^g3y9N?%z~rSH zVY)#z@IoDS@n3}ar+sIGM7*^mF4t)yjTK9D?}l#v%28}0p8jhR4fmY*yZ+TFblnoS zmqtTMyRJl`K#+6mA2sqjwFI8#aH)Kq)sL!|UT*A4WoYHea{z4RUj3@HTR_!m zZ$RFvCamwh&R_;EVXmJv4x@T{!chIObxjIejjfd_UGj#T{gNzahZn z!!JelBmey49D=JI8M&XzRr>p<{OwJPjl$)Z^+@Cru5C5J+8;g$Faz6q%wcz!zX~*D zsz^<@8q=InFKQzCtlt=x;aWSSBS%8HR1F6p>^a!u5b7Lq3$Q2EYo&4!-+M{kM9@Af z<=JC@i!nOlYL|ELqA|VJQ9=G1)S(0Pj@VDGMF@I|FRN6JE~&{E);=XHcdTG^AdO1ZD|gw_7(#ar#g~is40A$k@YA; z1>$yNa&!q${8po0HU=U+lDpgen+e(FgcBbExk=BHux|mW1wGQu=K^?7e{TRbqUy@! zIodElrgE;*FvRhhms}L7`5_08h4+9phMxZYx76Ic>xVOcK?9v>JDWK)w~%l8l63N5(#!cSh@<)+)-yxQ zhfH(aKv-a8VCFff(&>n(`Gf}>HzFy8Q8j#0`WPn=Es|83Tm;YYjwbHN`iv0THX|DKaQ!Q zSC-f-LB@wuo9Mt5lGbAFcd}q4Fe^a}y*TlqQyuK~4S|pYUspdAGrmzA4n-ExfyxXv z8f%_QIuwTh5LrQ~{iltC%VZr?K+`poCZ^IRO5b14N(G39;uQnJ_saEL)liK zk8sWbgwQX5ZMfegeh?8TG-d zhhv)fCdZp!Qj9?`TzQzMI6ujEHDvFT!JcGIqZRqjmTfGs+2_rH3nl@^vkA zpja+}_tK|%h$bB0+N&n^+f-#5(*Ha>rNtW){kHr5oeANDvqsST7a0+HZ;u@a2SCNA zB=oJ%HgTr$*6}@K2tg=mY4Du5Bm{K74ht*cy)5{{-Y+q4umag4IN2D9N~!;HBRidD zPrYsg4rKkH5~VpW{4c6^OYUAliOm*=1WB>M+MG6(C|5aKmC)NO2UBa{?z{Px{emo! z;XtOu(Ti!#2h*sw7149P0P$CP+82h3s1rN%-ELvO`~h4oEkQjroekQ48BRaFbouLk z@ap5Ie2Nns!B$Bno$598ftQ4TJ@b@2Y^bJXA8tl$VJ`BcBE9cHxSj4}mg@ZvY0nbN ztZ8d;ZFC#Vfcnz3NsG_!;UdFMRnA%tVM88^cEAe7gQ;fN5wB;(((gm{6xk3!ZTwXuJ(XOSVPx)2Lf&%RYHQ~Obh+8Lo z&MdYTgb;1Df_Qh6s<+v0}xEeig@ClBt}!2hcR7COYXYMj6t5 zjd&$=!M&zcBK(CHe_UaFO1d)ULyaKh*-(*!5od+^PK3wmynbUc5<0xr#oxut>#Fp2Iq0_Nq40LzHoH#m&*HK^&9fcXhD5z&i5a7Zji+o2#VdCW{|4uk;eN4 zN3raG`gzF^nhvLd23=+^`weEX!+Gew%;NYJmpxPvE#02N4ym0@4pSLAYbdR&!Pw%z z3iWSFaVqpyKr6qx@fNFo$2!m!eTKXJ_DAoT0?ynYLP|OLisCqMW&OtQsbuL-2#rD# zS#%)~!sC8`t@j3;>-4L&Cgo@t4)kww*n3g#rJ5LSBc>54X#rR&6QCg{Kig5VO9y$6 z&s(p8jDagGv6*PG+qd^q>9kJmcIiOZ2!vGY9#xZEEh0(}00!3#qbtHU^feEt7#yU5 za7}p#xZBU>$EdZB1=&&LrD<%3_sE#ga|7}#tYrP6OJEp`W(vA*V{2RG%f}WxstO*s zYW1LRlRMyxy0s74Ku5+CpC?j$A!vyRZJY`G+?}UY824kXtK3o!dkU-SuHNV|%H~wU z<*gQtxH(;6Y4#7MEu6ZIJ)`S%{_*lpl*)1z=&ZWsDe2x`_WJa38MzU2J<;YF#foz1xkcZ;KuU#xvT{gqr9V-l0(O}M>iF~~bwBqC1}&Jc=# zDr7}R2F^QqDcBj;Kyxk&FIV91u(mTt^$*CIr!6P3hrL2j%PxAHT=%sE9$c^YsYN@S zh%(_~lC2Psd##H2ouXAly3j>R5VziP()QE-6A8FlABNd|Br@S(SRrNI0|ukXB(Y6G zOUBWAppuA4>pYoKIqZsI;}W_b)aVjajQv`1c&Xj5E(1HL2V0h{95H`I@!?GA{)udA zC+(+`Q+!24!|^Z5ops+Hq0DMer|n&?)WHGWN#h%+=?jQPEqdKcb>8lE#lkN*||ii$K=oHk6^{F&HHibnsU3;y_!;EQGG6Mm{aWY zyqR=`3u9(s7v%>3Y)Ck+%b)5RLwZ-wb8$g8Z%;$smW!pFuet%1p@Ej!$r=LdGcAq)Kn6HZN z8)&lhR8ZXYWiT_lC~H413xZTK;Q2qjA=gR?Yg6!UwOgXKakHU>9v5IJ&RBTH#<3wq z>QCQnvNqJvlwxh5RnvykyLi+#CMt{zAnX_z_(EE}YF34!>pFw}CIoASSdAV1odKVOlk91L&5G?aMJ`Xs{Lj_L!L2eOxz1VnU4OW+U>Gb!}3jr|n2Y_}!oIoR-aK zN0mTMZKe_<+BLpsFN0N3=4B~IAsYEwKgIsbxQL0iXclzrc5CI+uRjUA=~J{Qw;sz+XSF1tIJ+U)&#?(q9mIM{3x zGCu@5pJ1IiTPAYu_ByPdJU*FJ9?ENsn_vI**p4;TiK2wo?Dlg~g)vgc`jF`I644~5 zbd_1B)^c+7KPdcCkO`Ell@iNEhM1faiIcd+p3F`Idy_zxIclw9lV*;-PHZ=fQW^x>%E)qz6y%jd-wy`B> zexmn}N2iUm@j*S|q&qAeLM`4R>>L+Omr^+L;)FnoZzz<3YL38!14qif6-5ciE)||b#-xJ zdAitmrH|&&jXs=nN+*-eU!ZjY1gPkAZu+R{R4hH!2)0CjPT<;nG1TwIzORIz{ms8X zpWC-BWHVMzVSk>wZXfu+?88_sJ4HXkb`TXEtJ;zU+Ax7%{xUO_??)pQ2XS@535>CDyGuhGOwf1 znX~%r1?xqCFSo7L)%1W@3b7;PIflwqf8ZhBCwYD#cBj;mu(^HPB8x5P@!5J!10b-J zHwK&GeDrqagGOi~VYDmDwrsLzDee-*NPwPFrNZv!p?YANOXlg9fl}#izb=&w7NbL5 zp}ZDn68FpHPnQZL%>4{ei;L>K+i z05iN>Rm+t{JV(^QQb09iWINPIH;e1?`7GJz&5*1FICTJOPDVqvi%8bT|8+})F3=3E zjCmo(+;Bg_*iJ+O1jWSkQb<_0Az8FN^sK0o{YYvHpO?>Ux+wv~)F;~O z^E}clpdmvpmtB-Th1#FXVp5gm>IN}(lslG&B*E3o9<{|JT2QIimR&(|sUu=^3&xk~ zQYs|OPF;b{95MQWh&&;bg7cxY9$FIXc zET$=EaUG;yFPH^X@3g$GY_B6Rz5S7p^${rkE*0&3MWUirPOqt1^ez7iytTGJPL{t5 zILi>Lm&ZZyH~(5Cj3&atJQy6Bj9IFI#|>K-GuZ!Zw1Fj%U4nbDFfuhE`6ytE(ZL2CkreyGF980;Cq59203ZU`A#D*$DC~KBya>` zqM>B1a$xl}yo4ZUI!6a@S)^K|jvywBt2Lm*Ng%vFy5zx+ zfotmEju*8LauYV&B}{yb(4*Q1A!FFAXM}{+68fP~hZ;u&~cQG^K0O=o06PA-sc-dN>z$vq72H7lT{Dg$_Ug5i3e-T+nE zU@o_nKx(!J41m@as|oKHU!i_XScSdq0v=f0Jtjkm&G|J#hJ?jaM+*~t1UWT&Rov_P zi&E$qpxJJf4T?NH+0|kbnJx6~pGenAd1Jh}wuqkOl9xYqcYO);bnUH~jghV^XGFcl zop2lINr5HaKl2$vVKv*FTRPTq=Tkr{dWSrM-~4@|<3}h0g*|%TgC*RjqYsb#XC;nc z)`doc{xO>S$m@_xLHH-C8jv|75NVTr0_kMGx&35IIvP3OXX7N`q5<8~eUKrC5~7g2 zheAsCvc#0K`~mnu)*P{(XMWpkFc^}YrpffW(dHXO@z^VUP^WE#ZoK|2^epAp2C?oK zVjLVlts~;9g1!J4JTOg>7PAL`w@AEk4y{~Yc3q`5NT8>GuC|NzQ9&DU310i`0d=Kd zEYi%s;Ak0+jJ}ucs_umAWG%z*`~$(*=@qre)H` z1o1Ljtq*xt{o;ehB;Vjz!uxS>*t?G>AKPdC2K~hK{0Fumxk^BJ)Z2@~Roze-75B#s znK^sf#jPknHrofCfAH6PoJ_xqi7m$dgPMZSlG~^ePr*7}a+pHpx0-jq&bcY`AeG?Z zTRVmf$e=YyCEQ--2pq5>|4urx$uYy{O>RT!#*!2g)cFY0!k0F>E2!IuCm>&nr@a&iJhaYwM68&j^v`{J0h?*YZ4iYcFMxkQ3ko6L$Lf_}nrg zh8xCmotBNU6Hjhu#>!0gzQ>{x=XU`n-@rDw_jydoSz*_oOGJAQ-~Ym${OaZ~!r)1U z^WCoRG)E@0OPys?vp*FCd9Onmha$w?aGrF+#53^$EYNtqzpIH;E$}H(%%@9w?*-jv z&jPbX7JgDzNP|+tUq1FhMQuFtAGlCBSCRRVljEM8Q&ML&s|+fh5m7vbMoD_PbU!Y_ zvp7JXn8Ln+FVkPL*;X2S&H8d*#+|09ZI#zz+b>W{K3vC+5`9tjG342ldN-gD5a;u-oz>O^W#wRv z1j3tG3{dYdiYN61UUW*CfJaUY^l7Q4DSakPV|tp$YCg6(SJV;}EiRrDzKIBv0$M>@ zz}CpKi+BMXO=YE$>nrT8Ajo_KRONxml))syFuliHE6j1oyYA zht#XG@YX=+D@ze)HDaWNCIz}ye=ryF%6w1(UdwTtb-iuml&qUZmddh;fvg-Rk5-HG z5iT{{u7&mwzY8rhpCfM_h7oH0(1~R%*czA9w)^-9tMj(JKD>fzJzY;$(wnZs9xo0n zrVSrGfL-&;wpG*K4UF%)1XRamZ&9xB#2`?vN}=_}xvIAe7~%8pldW$;Nqchg#&O%wt7x8H+~>`z$`$Jx zq^4x1A6`!&yOUfRv$+Vo3&K}J7q%Q6|=YGVYzMh!FRxM9#4+Wa{;|gDcby<^_ zm_dH5cfu0~i<}E`hx^Zyugo<0+Lt^*9PV{R)K#67Ifcl%UxC>RpxMJ1zn`#d42YaK zY*8Ab3OrZ8AaettxYYjl+X8NgXEs2O@zQAz*~P7Xa!8!{UzAs!|4uVSfvrP)2K z!fC=3q4qo{hMwDdzM3$rdkWidt?GPGF)1PZ>X5hS>%DUMQ=`D0fI1rV^wa>OA;DJ- zeo+q|c*Bx8T1Kd4TW&r&JDZ=eB$$W%U1%Y?T~+JNIDc|AD2BC@FiB7ItE~5Q6gOR( zT-K&JY~L!V^OhKy@K7RkRP7|#N-Sp%DZ~+k(Vp*@x373Nm0)@*UMmOLA7zyAj4VGb zc+JN65tPTBu!soAtTu#sqJ`sc8>L3DA+C!5lHXq{tuwAO1ifbdl{!w!&w%h?DqZG0(? zGm)IHq2aP%G+;es_{2~$3vqVD7{{sXm18Ss{-@4VZt$Na*{#FUYK=uwVpTyKaI`6K z?P3W1=?npzwiL=VO1>)8x5ldXu7#qbym;t&V%~;RT*)vtcvqIBEenMmfgAyW>V3oOd-%u=rK(l{mgj1j$gp-KI2 zR3WS@yF1e2mlbvL56ao7c!|vD3&Umy=cJ=4Zv92xw#FJHvP`?Uy=sMW`Tip!*mN2! z1y*jGY>43|NJ^wP-u2_Vy8P1;hmUWEWRX~yaMCe~&CTcZ-R%pn`bv{H*4B?{82)Py zv_D$=bPthW88-;CNP!LT!Yp0bLlFn*$5DUuDC|XX-A-GSU@$GF|IX70A~*)WG|LEv~#A& zwC%7J+tE+{-o)(N?V!$Vzf^z<0kk|^5B)U%U4Qh1aPDZ}#>0OIA;IO4ez0FM^f9cW zZ8bE$5+qNeHAdHX)|(2Gw9*(2#WRy##BaHEcy6Cmb7cPuCa>1UT5Xy3enD<4Aeq)} zCO^K;9pToSy*o{9Dp+!}Vro+E0#&i^38T6lx7@)qQ0;isuZcH!sSb%8DFNy+G}GOf zyzL-5a@l=@?F9TR1aXx z{KXax58Qb~+vcJq`7!L3ho-;<)w{^uyS^6erLq)S0YzLD;1`Kfh;H_oN=mG}^Eb-% zC|NV#P4w(C42uyO#LE|?ptM}g;%`c#Zf{f;&2zWYp2bz^wtHWf*RYG)%7r{ zx;{I}33Jj}Zo1tUn(XZW_dKmygofo({qS-K8M5xJl#+%tY>ade7kQP#G!fw6eHbwA zS7#x4x7%y|b{Ac_>tYu-96;{B)zIGay5PV3Uk1<0Qws49opeg0jjL|HfD--}|2(-CeK|KyT&?RB5>&mR7@?dn z3{*hbgZ-kWOu{z)>KOGJbf+^pW$O`viJj7XLy6~m9P#Sr9&ZOwQT>IEy3N6p! zt#pjS)rprgk6H892KX@<>uAQvlJxKJye z?-pnmHASAEM>`j8dbRTuE{6ZxH=A4^#k^aTRgc9iL$E<2ZDh;4i8pN80GgHzch8&B zm!q`zjRMukr+;oeRt>=ZrrLOu>)C$BJti0B$QAuYr3kq37`HDI9U~FK$1jtT^X3P) z6#-g)J*O@H_3UDFjI~t))H9m-$cHP+2s4s6DNE4aK&?}uQt52&WiO?PRw1Nv@vj0- z413*khTT3z(aK5N4n6~Q9?vqM4@9d)eqL1LBPCe`=1KP}%7_Q!m0b|TZA|)Ko3%Ue zi+!RrKpN_t#cNeayACR&3h(hpWt>5|KnJkO!D`AYO3#hedzj5*lb(!&>|vV$PoA4T zA*&96h7esC)@PJJEUizMmzWi)eDJ%Bd`D+@(NkqAXo<0kbqdSHzR;NthIS$ddNo^| zNEI|?niuY_znV|3N}IIMX9Vt!q5ET?tkS4b`0|YF;31~mdoeM7D#J>XvZyt=ISMZ* zfSmVF-r~t$pbe>3Y$(n=fQ`?Vs=6kARFS4nW7Zpp5v7Z~ha{SxIuIl|&tpj2vrijn zSIeEp#8uqu5$;SfzaWCb3~MPdP7KkpBPmV1gBGw!Ho%>Q8m`iV4+J0cO=IFsC4`|6 z&(GbzsE6`;qDlWIiyC4~erd%w@b^1=TQ^nTv+ltg9pU#am&QpOdVHe0KNa-VNP;Pw z86}2We{3-Ii#~Xr*kTuhc`O%VMJIiwUdqduD%+&W7171hX|$ohGMReRwjLdu%!HhZ zlZ1bBg+;Ys`f7yjt_V&*D0e~=L#jhTK=0v+DqbS_I4jN|-8 zf)w{i49LB*u{PCs>8yThSC)J<9x|d_!Lv%#d$BL~kJylTS0_cjk9*KlddN`}C`bDI zqxP5nxAvb_tK@2PGBk%(#@n&iOD*shKAeO(yqph3wHHgSf*!BI&iBtoKvWpD<1S+3 z1Mt6BN*~{*_e$d^@?L-I&FjVEN~Z7dd{tMMrry>DhWsq+Vh3s%YZHv9`^KNbn{LtC z1k3$?pic!~*pD)M{JXX&*;Vb--q$LFZlQPc4+UCRNR4+G8}h>e>Myc=mhS^zPHbKu zp|u#1f-lM3;Xj}-;&!0g89!hN9H0zN(MBXKq(leeWFC>arP*#M-q}TW{1@*SoA9xjlMCkpU^Q`n9rQ3AgTa0FO{*y<2xYUE+i&uBq zZn_PQ$#ux|g=mJUF=TS+z#I(qORGP*)z!861dSHj^+>Q9*|N-CdMNIomOlQ$r801m zU6rB=9y-MV>m{PG0QO95R)&)F71{@Fr)n8eg@PcO5xbpV&AFBHK3{jWXkdu`WCKR{ zrELRAWzB@wGQIO!a&S*YAX(&kJ7=0<%Q&z;@kd?9_e(`NX4-4>>g9XZW7vH)o^0Fr zWA=o46z?P+Hk@AFdc+Wcr))5)C%Ag}?5R#JwR=y7Yb~v9LT-Nj^bQiCb`y-&yo-Ja zUay1rs4mt{T}P8VZRW&j|DCn>WfuA~889$^7zAe_F)R<^-mSs?MD82{b)*TBdM(bz7Om!hsSl+R@Il( zLBZ-GWF5$R&SLIdoh&e>7Yyx9l&kET(tI4q$?_nh;Qdmh>La5CH*jApT|N-lPMm>h z?vSdG0Zt1GDL~Nx5cF>hWd>9*l)!d^y`}>ZX>+24kR~s@(9mMy@+5o;;@5HviX6`I zr|i=rK9U5+CW%!r%D!$oZ+{`aufbI+uwvK0#qgrvOA4#sxQ%XyDvwWbl?VOq$9+Av z{{7%funFlUe|{_5e8vCP`OciUFOvIWzWK_2v|85miad$*KC}2fD*9r)@j2ke`z^xh zU8RwiqWz^->}K7RUiRLlIPwMA{#hmFR&4pftNlI5{>{ASDd70i%iqa2Y1Du zNWk&oGW;udCnN`Q{ciIR*aq`*ubbKWpne#e)0&-Q`L21I zb&;s@egk>u(@nKMfB&;mVfH`CJvJYpt?b3@arbBP7;&#mjE|UgKGy$W>m0x93g30T zVw;W4#*MXNtFhG>jcpr^y^_XGV<#&O8r!ywhCOSav44A?4`+<^2h0y^%=x^}d*9df zD>bhh3-{SusvK=?1BwNzZp%5wYOg80gi3@>%K^RvO%Jg=kqbje9;&d_|4WsXDUH(a|84lvFPZYF;0aTqrT{vGN#ksgK0A7E(X1%iz`!CY>`ORG%@D~Yh zP#Q6nT2&H87Rg$H`S-pSmH;v*#K+Ksji8V$<$fNTe&2O;h}kpwp7!QqwPa1=AS2Rt z*$#~d;@*Ae!%BmV)>*A zkJvp)u8e!h#r>>S$f-6W*Ae0-e4SOIezLIVW2J{6=T+c?3Wzl zoSWy1VIHzw@tt9aQ$lc+cQKToNF($gWEZ7=Du3c!ao^dK8a!R^Zjj)u!I>joK$qId zp2X*Rk=JA)=7S~lmS^H)8d!r7c70?OBimw~=8jq9`y>&LOTiMciuq_W7IN@D&Aq~F z+)BmQx+?ifUolS^6{~5rmx!aHOj{laT>ifEfv-qjqCK5s=FJPm#U4loopZ2_d<3&) zhz`XE{W1jF8ufL$>A5|WHH=EBbB}SWw5D|k1M=~;QO|}kw|xuK?4|vNFNM3AaEB;!nh&pY_8^inX%-gm3n@RX5}(Ay7>sKSiba5N0L&z+`}u9z)=gG z_(G9AbGM635?Hq(SGvycj=o`;Xou+Z){_*19iGigZz2!FvHQO8!^D>zEmJp%HQo(T z|H(ktsM5@bOx)*xFS)H2cT2K=@p`oh6NF)_qVLO|1P7Pf-y6fTZ(G}m*`wVZ#krvB zT*0mRpELbANh8tIjn}um{%sf45&ctBOcCZ1e-Zp-#50l$*hfE`r?D2aF4Az!d>-U) zq7&Gk_JupdSRM4-tsJ5y6WKt2C<5iKZ1|z)xgPE^o=66G3l9ZMyKiZWs>y1vleM1o z*HsSG%@nTp@fj?dgMK*3MPeHuM<`4KE0NV>}y#pJox&@-yQGKdbHIyxU-(ahBGh<5pIMnpbZuA zY73ITE*~EM;6<#O%IHtQvqtfV4+3A7aL06p=ZQbm+F(*7{gbWj60?}#%J1(G_6;I= zz-17Erz7CG({{{?+!1c3(b!9P$!r)^?m+blgrwE%=sK2vMBDpoHk^?-WM2IOB*~&X zaVa!bZcJXwD8Xh|FkCjMO!Qa2@+?w?)0QM*W8ouX+VVK=lOavVxtJ%-wS5V56*H(f zJx7WX#x)r4aOlg;igOES)Vr-zf~KH=mC`ZPNmNF4$___Ca=AmDcP5n)pk!u$rj-x0UukoWT?x#kV4!h+aq{&XpknHqgoP-=@HYAaBY2cYz z5;`e5F}pv_rY_v_CQsYN4~g=%FVLX+pwx)G1c}&?CZ2I}gv4%LlU+X}M#9SXOL!1) znJ^5dg$FTdRF+K8<=a)N>J|3jwLO}fpq!1OL7Ns-CDjC$DGnrUUvQ!7m+^sm+Rr}d z>y{c%k1SK_yg_)iqCX;L-=n#waPG#s^u1I zOhY~q8drP=krJrawe$(uquq4f2pmb~WW@KQU7U(P{Ycd3&Tm_NBFyNz{$!f3dPP6~ z8h8JTqivO`cPeahyAooMta(Bm6|Sf0O@c~aWAVO5zrM~gI(vYcf&q$B5Y6_5FKn-C za{RO3i}VGZnTv=r=YOPADLPy1LO7fUZ239|ndKwI%?T1ch~Tfjpe4-$VE`gP3*I(! zJutIpGfx5yAQmC-Q@q+uj?B%;U^fgKjT=+-lw~`f0bytE-IKy?e&MXx78`skQIq;x zvi;^Tbc?HV(>`re_;iv1mrXr75O!fIgtCb`gSXkU7+S8TlV)I37&Rz)notT$&fYel zR=yvA_)g>tn#L7?`yz)JuW87L$5)qxJ0ngA)sB#PNCRZ%p!+mn0pS4xut&R4_&ncy zM4N5{yvp5|q6HA<8O=IzV5^8q8zFhvFYt%)0xxExAEq_dQ9$WB5fx(|ttKVfwF388 zTphdgF4@B>RLy<$v!!w7{6K5OJ=lLR_hgP_% zROgf-SEw9W=Vb!GMAhjZ2EL?p|559rih}_;OWogmw?n{REB(I0z^`2;=wH~`Mo(abhXVNxy6iz6s*iC&WuH5*t>d|i(ps~EpL%=);zLKgzUF3l)Z%0IB?9RWVnweOB*7v-2&}0;x&mdS^IZ>FS}>>DRmDN46c%T z$AvvA-wx*fCPKWxT24>CQa%pL2^yfSOITCtY|u~PbKU3Hj+P=gW0s%)KIgx$PV=9m z-bydDSWpyX%9@oJbdpIq4j^p2mS)B0Ri{@Q;bpW!-Qw1ZNUy&;N^u5W@u(mF(m&CZ zAfPen%pjAEOgrXN0VoxO7Qzrt`Q0yyLC zF9GQ@;iz>rrc&6W)hHyTvfihE66}WUIs=VX(qn55CZH` zP$=>(Qg@NDl~lPnoKI%j`j~u^8QG!}YvnTkiS5)h9P7mgw^?;NUG4EZg&;eGv(5S6 zn362+JoCEZD5ley`OKw=d3NZrae%N96ZmU#i<&S78}l#3gyEnA#-dD&(H9DayRcUV zSvI7TR{}>=HB46G(BR?rweJT<4pAA=K(p-~zY<|xk+}%l=QQIkhgIf(q-=0IO-25$ zeJ_MgFWkJFZGcFOkb476(Y)zPjA{O&>FryT+5gvuO>iq5r zWuZv{Mt$*XS7yK(l@6iGp6LM{awT1~;*Ddd=J2 zguY~D!LFL-?LOsM(tCCUcab!GD63*VmLD08h^SOZ{sRoQRnI{T#31k;GCSRaZ^h7; z;;Wgy`y`9RIR!bxv_!@|IDo~(L{~}4J4#0S&YfW`7T&@J7F92?^`I{U?4DGKShvW^ zA3GC5nd&-GRh&4^YO^5SepB(xlo?cjq+ljNRWXcEQ)i|IP$fy|ZKDKX1@h9tYMge7 zt@I+GctBL@v^pA?nWlIyQMLFhQe+|iFDr_&X$6Lx5fyd~SBFJ^CK-J;=uOe98rkXj zavA3Ef%2YzXdsuO7aRWdI>$mox&~V3lDb8(@s*=)6P@vU%nLhI#IfuVvf&DXsoj8} z0HScNhdFW@Kw<&HXcXsb3ZxF_H07jfu9501in0y;xn`FFt7uF&8ro zi9pjgqRIN~gh{h05~h@#bp!$j@Tu=1mrJ^!q+(UP{>wG@J7|3DZ&;rGLd|st9~th+ zZ^?B1`35$#f`T;(Gti43CTp6j^{|XP69AK;-m+fHMvx}nP#Xp4n=|f+;`NS#a;Or7 ztg<_2CB~4Oc#%25O{w3f=v(2%m~@9M{OwpMnaXr;JsJ9dmCGcz7)41+#wr&29}g9- zlnA5g%*r_pF=px>hKX4t*|C_v_mun-L_J4iWH-V_41cMLHgxp`H=Lcn zP;9&bsMZj?pdhkEpB*|5QkYZZ? za~^Ia`7{pjEQJDBtF4S}b=aQ3&sD6O4^w>25SSA*Ceime^1#LVs7U1W7E09%!06R= zeql9#SMIP2N-Z3}ocaWPJV06@l!!q0Mhs&qBinAWab}FHr)90t_3RnqMkgd<7*)JX zW`C)<(#Yt=R#K=GjrkG&XT*(TXDQk>Ue3Wyt?dvFRccFcKG_aAEQ-2M7n2$GpfaN#llu{sF1%1p1B$V5sz`_~WB67q7x z62T$9@{CQkoRfvhp5( zEu@%xGYMX_kd*LMy*&}gYh8~S;35YFekYT4p2GbG~C|6*j?Efp61CQl$$7Xf>7b!z)t>mj9viY}N{FyG1fjEMB( zSP825qgof~z8#SIDuj)t87ybr=t?oK2ZIs&tm*uwnhbdtx8K{TLlI$*I_vy=4sN3r z6X7V|+$2+U$P|Dl^YXa`APHk`N;r0ZU90NinS4YlPKRaRfG&#3|yosN9;x>t`u*zyz7bw(tBM` zKCe;XFfjqkmqb>+;_-bNZv8?LZdCE$T&D(VjN=|3PNIiqQKjFFTud0=QosoKaiem^ zu_{Equ2!3(_-l}BhFSK82uv1)AC~Y*?A3G5?CUGH&sg10=o35vjP=gKuq}i<)JS=c z1cMx2{lxU3dm`1#A-!|C95MiXk>n`lqdTEV5F#yZ*XA9UMnY81?xkn}1-JNV*rh@8 zI?p%*RRp%nm;&r96D&+Pb$ZTZQ8{I%PwQ0GO;_a=aV=Mo!SDdn$PsW&K)ae3R+1m_G&$W9 zn$RM)V56!50W^VrrxoR6A?)JNK+~uCPg=%`A2P+mjS-WF9vir6(_G=Ar%0$$3eZ%O zG&b?VXn9g)HOyJn2W--ccZ3(MM2JPJRxnwsc_*?b_}_)WFu(f}sW7nDz+Oaaa>p37 zDA7QK3`D1tAbZHLvEAn2>Py)&kkC7K1Eke|w`LrZwcZS{Pda1%=n4EwIItF@oODt+dGXaknQ2b!VoMu&^yKIyH#>?%CA57py)TO(m?lxe5*)v znyk5Xef8IdKRAQ01{zR*vt#&vqQbh69}M>h!2IH&Q~sH_9#3|1dH`1O6Z%;~9WmI# z+?eE(>IEKH!ls&zT*=Sc+(HC5p^67?n?-%o_!IpU3XI4+)9v`-4v^oI%^qBeS zL61ib7?ten5Gb30r(7ar)cetHlNZ!5g+dSTX9mwug^J*J&%et~Zxf$x+%Giog8G9G zm%|e!gDvqMdGzuAK0te$lbtoYlScbw3=4(Rli4dmY-6SuSw*_Y@Et7hvsClYs#W9l zvl3pAWIP2>NI!@q$PzKeZFfp90hoaA=JdJw3-tCRF>io77unJyLQ1%z;UQmhvrX^;xw%-MV~q z3ct1x@<(8e*?Ve!(iE=Wo!sVW*tNG#hoq(PKa$6Wo_UYRtjDwpu?rE9@4Z7f?cpO; zI)9foyK$h~lliTAd31X-X(4&)_)`jwP!Pn#DcHgqUUT z0OYGQUx`*Z%)E&qbup;56sl^d8^7cEaK|0E`_so4LdY{bOHe#@T`p~sW|wNovSSI& z;X=+ec}PmWs$-Jq%}_#r(Zj_uUWZ`PL7Z-htIP4sFmv!1coT2oAx>n+huVYh84l~Q z3I0gio4o$4)?Cb2{gs91^ca1aZ^b&f(ft$0!3H@DZhD(q0pClOx-^W``ELWxK3B7b z;u-!4qPv&>rJ-=%MygFiTjY?Qlo#|k6f&V1nN&b~{oXM!6xJwhOHjW$vGw|)kI}>s z>fFyySMrl@S-Z5MA<3+?{|9n>U0#09yU{Dz>C*I}Nwlb2f`32>ezbnXBIMhg8bNW$ zVdjsxdD_8zg&fL zC&=^#33neeP$3HVP~dK+Q0JPoWcDl`_ozakp(Fnh2P@SG;OSz;)4OEZj*>>KKl_bE z+=~^u4xQAIsUGpo7l#x3>)CD*4pbx3V)_We9Gvvo4*r7T7uS>UF~VdMT5cS*!Q)3U za^p!bHerW|>Pl7mL1uk#4U`3_OgYrWwBzKNpR5^8pBI+j^uKX`su9z`1f(+Fg8XSn z*n9a>b)5eWz#Xuf`x1qCjQ^0a$H0$+#X)I2f7^+S_xsC*5%3xluWa_NgBkD?Y-WSr zIF5923Cw>aVH9ur)luo~rS3Z@z|hf_Of>KBErV#MgO`HnolS?on0r)%8i&~j!mXCQ z)vb=wI-q}JrD_{Vi?x&s%Ec!$a|t1{JmyF=ac3-l(pXPqLxI+LP-bJsXdzC)HRZZ& zBW-~+vJ}a@q{RF^hi%7kUrc|Jr;hSn7xDbgfcr%&JK;A80g;vb==g~cG_zDB>=eSZ z5He7HYKMxtUR^|2LYW^egqTAW*tL8V9O;0=SFM83q?lPh&^j;*WX|WMQf#qB#KGxg zj$b;JBj%{J#Qcr2Q~F>7zD-E7EN@5FQG@h5Nj~Z+dTP@@M;j`RGf&>RhQn*MoI=t4 zBH+*u7x1SW?mFnRbvB_bKQPf0gO{j9z6`iWjmVlu8j|=? zYZa`q*D$Z>(v}S$)tT_=MN7PnZ%C~{mT&Gyy)88F&tcV3iJv$S!bm!m!!lu{>iOx? zf;9~goeM-*{7H&`Z%09gvXgl>JTu|`Q0Sk=EdEnGy8lh6MgqtNUyhK~GTG^6XrMF< z6=Kc)>Q?FqW!dN7q8aqy3>#9NskgP-v4stj`JCe66E0ob{*|PibLd-FYC@bfPTKq# zC1EAF^l=>E=Kqac(KvHI&WbK3R``eq>Y!)G^WX4#)#Dt&WXee_oJ$to+FKDWZ4FW_ zqB63EMF_e{!9f&{R8bLjv-oZW&{iTxj;&H1D4@Lt!zJyV8<=L^hV2(uMU@eZzIs`b zXa#3_zNRkC5c52@Shb}J(p5dYKJjzG8pHB~P_+3uL5gJ&-@vtFok(Zqea|^TF5jc` zEc%99eL+ewZ&4w5uPQd98u`QaIYN< z(LW$zdt!ya4cC|8h3^VHKI|mvSl3IRfrn?U2x9yRCXlbvR5IUDn`=Cx^)XdU!9M{G zO24mN&%Q33g4z9~x}{MUN-a|`hiuJu0Yd*4!US+WL_~QN3s8*ynOQnHJY}gMznM-8 z*d7YMzXYxdbXfUDLDu;Z?XNYvAD(`jHa34B|4lm6woLIqNTBXFzcI0Ur^7z=)+Xu>p-roG1@xA;T5h)Kws0U9lMH~Pb6(1|eV`Pur#$d+p@Thgv-e;3$jdvTed?(-!h2zx6|-~_W_x8BEei~#?p)cyTQ{QJFe>ft_ z7$@O{`-qV4YacBE;K(ZpL zPRqIIfxzLTh>^dHOAWam_#DHfLqvlN7WXP8k3mAxG^mK>)tVDp*)B)1H!?NjCLzu& zR@2+EN$5gow78Wok$5$)f!9att`s>WosO%-ntF)YI`gy3t2VwXhgCaR&wu(dzY0|a zc=6+&bSPiCE4i$cWC<@!%?rZ{4Q#Dv6Sq?=CY;Y6A-ZV!UOmJZqM5zGw9?cdpBV@M zYZYqRVDJuJqV~xfNEtA}v29T9B%wN+r`5~V%l(2CBb23$SZFDGyxTw@#+`N9$#dEO~?Z63* zox9k876P31Z&YUXus3k}vle4^@tb(dI3%5*m@bg{y&kn)Yqr9#|JAkmB*#zZ>Up+j z8J!4e*;~v@oNCTHz7oU@B`w!U@_qSMhNA15?-{AHw&j2xF={(fn@uWH(x{XUDMrrQ zmMP9N-h*0E%3r?ylK;g-AxO|s%Tut7;mCdJzehm86r?F#vhmLm$cLe!=R?a0ByxJ@ zG4Y3~4(ur^iK|DtB`6VIi9sjb;)M^^5-yNYz07s)Z3%cs{;3^DUWvLkhn~0fAYov_ z9thG2LT}!d_$wUBRok@tWf(y+Uraoi4A%};c}vPj<`dXW!|urQa0y;1zyUoLqnxWg zTMz*#oRAKCL5Rf@*~sNgG_?@+3X4_qljPAH0m@%^?`zFQ2iuas(AP39!XNegyMt2} zt5QzA9!L<-snLIGkixp4j7vXQZHW8ojKEoh#DXp;7WxROwZ0; z{RUNGn5n|Olqj(n2VI-3M;Ww?i$OB$ixQnOi5n8MHv667-4{F59 z(G0YmmfGjP>T?>)jFnG8Un0<*&z-=K8)41oIQmMNSZab6+kQim$iI@c*8GTO8Z=IE zWu<*ZkTB(J#Wk=8KWq*R>Kn@8Wkk~%$9F<0C&s9l0kr~r%n+qxubp?M{d9?QSHB)b zIW++BAR{Hg`7dDAt3@kTSHx=l25nnyP;0u<#mCpEVw<2z=V@IR5S1?(l!8#B3!|-F z_??C(7V=K@22X{a=GsdO+1>(o(WiNL9!1#FTwoz#NoT?V96MDefiMy^C#PFAN6XpOl8|kC~Dv$Np-ezKR+DI z?WN9kE$ok%?knO@<)tju{UbGRlu{F=w$E|54Ze->;V#9zF2aB@K`8-5)+-$F56aTz ztdA$XeINheoy3o$EtrvopepsLb`r8;>ea*FS|IxnRI(R(Nu*yUvM+C8FC+*%m;-m~sO zTimeoIGKQ3lns4Zn7cj$HRNPl!{5q;U+OR<${l=4@${CNc8NS%3aJ~g)@Pthum%h; z<}X)p`W}E|EiNQ-^5XYUx;bi}iL&kJQX}vq=f?iuUAuS}EccByB>pwsH4_4do%cioFV;5!*3XaNE-wk?-HbPdL#x0ktYs{fEk| zgW>xUAdys!SD$7RJn&s{+r&q$0Z$Rr{>`x&dI-y9Nzrws~ztfWX4<6@4&>Z0TF$rl={>gi{~5d;V;Hu>Ucw(YzMVvRa7_=@r&X+Qo<=!$+v zx54A^^3jZd^{cuswIRTF>ZVFQd=JwHvxsV1g38U0(b~IZ+mAp2H~%zb%?k-5t^aSR zq6y*p_nMKZ{Z@5vLG}3cA0!US%bPSb|8&)x!1iGRAuo zTH!jUryw6uC?yX}R|PsGY3vc^)|QBCE(r|PRT8fx9_>&)PX?&a#0WNyG09`DX zzDEz9eK;HgNMyTfOvk~W->*FH>U{d@jnlsTbUZ9)Aog8vZxvG+MrrPfL)J6a$@GuO zB*K8+c!;$EXaRM<(F5I9fcN*GU-D{}~MIe0Y|Aa#2}| zv9;YiP1j9e&qU}5HSpbjn4%KTb9P#dRKuZxF4|)BF0Q-D(;q0*taH@%ZDCW!Da@i^f#RLLk~bwnYwM=eieP%s$(M5sk^vQ#gN1x4mj z?YE#!aeUKf-sbVXe@F}rY{A+8yChAx3OX zvf*)Ek)7Fm)?N)+M7iCEIJ&RE86JjkLE0+EO5sCa**^zh9-ikv>n-&*kCzUjai%6R zE-Vw@1KL>7A0Mr8;vmA}TA?GeKUt??Xa!!H?cNwo5> zF?~~h3;=|m{(deod+DOewSm!2Y}Yqk`184_k`YGx$UCtIO<%%qBgshUra_E`tMC3a z;YOpgTvwY?hQQmotsVa)cd_TWqpS`xzQdJQ3-nx6vKj8%1Gi0uOeYFOW1V4USq3|x z+cf1jVD!QRP6BiudN4`-Nwur$9rqf~x}#GnsEEGgA)wL)gXJ^Z=*7F32*w_`+~mVr z`nDE^IP8lek?U@4wH>vRjT!)Ek+%Y$+hSjW_tb3%AdId^2r!ozG(6qdlYo^@fItE05+& z0si|{*mPEjFy>mv2TLT`Dm}IDX6tsb5}CD$l)c@g_Bxsk!iOT-LLkQ!+T+v$h1dGk z@O8`}eCktYC-4Bgt1hCV-XJjWCEA?wbIh`yN^T2-)-&97k)etG%h!$sF?N4|3L$_( zW1|_zBbqT#SylfZs^J{n&%1KyP676vn?=uPJZ%}#FzMRrdf>YL@;3$-m4VA@?Q7;O zuC5t0y{ZU3&I{}U=E2{OAfQi)Z|G%#IUShNFjG;<3Ww`{)QepvnV(7+(k_5+ujc82 zxlfuwZ|{`0-tS;ln@;!xJ<`w$LLq^l&jUk(ujOdSF+~E{6!y5cw)~*YlAg_xMa(?) z^)~6HpK7T*;X2?Z%X^c_suq@)%(NmcbherQdY{0~^Q<6102hsj zIsb#~TvMq#@JyDyl#!*{kEDK13&C5Dw_qUe4t`$GE+Q$mbD00!N9yEVz#fRq=NA|1 z)7S>gfjji@CsLPjEyNN#dciMT&dvtZq}THz$0f$rE?@43S1PtaA~hZV6R8>WR!sL+ zn!*3K%v}8oqfdy!o-W~FK`?q6^5r0)fMvEvgUIpBI1VVq-N0`yCuV{~kXT;#*U5=A zyfGg{n1JOSAL_P3@n3E;#5PU%&|ZX51h>2mC^``Z&E%*}`Y**e<)0lf2lKNtoYUG-ve;yrn7Vo5=YsO$_F;s0}%WP3h6EUwNoktS8i`uX!vM!DhNf}$MjE_ zeJKE78HilBq#1@6meaYMbvJ6!=kRXAW*Y@Zd#=pJnR;{4m;*U!b90Ie?!vC+F$M{a z*B{rj#^P!eMdj*_6%sgZ`@lCagjhX?UmGuMRn4)Y$MZ+DMF0%d{2?077Ysj?c3U_NaS=)8Y1w>TMrw>Uh@=Ra3r4jv&pjH8UvG z4zfKI%Rr)#GWcA0C?^ed)Qy--=Z{8g7f+A$dyz?n^Bf1^{h2ZR;JArhsB)tjYMW9w zo2uL1JOC+0>x`Q6&t!@P?U(vr$R?dC8*saSU*n6uDVXA2VYXXp!0(A{?w;}dKqz_m zP2^$zs}9MScPe)JbWTv7gFp<%i98-J)U{Nz3~Yau5ze$?VH~wi$-=@^bw9_I<=ZUnIIctA3Yc0*tAJREpi>Z)tIx)#WXc z<1+m0`*)gMSYLC4;&tt(i7${qE|!@BZh#1lF6@X1zJ=$KWj#s9!2{i=y*0;{I(d$c zOk$PEI$96LUkI13VJMrb^dHo|mH3E0t_e@!G&0qUP`_Hl;K_TXP64#?7F_jrxtwJ! z_}2%;QMEfOkU2}4LOkspFj?3wo8;>1{z%I`F{JYo}LD^dES7SUNPhKqw4=!=23~c%Hg5n z(f4qgNGS7o<$G+7I!?<+t>gCjK9RKXR=GqfVWFNLgxK6{kb>JOKI=zTJdFmS6J}_u zKQi?>KGRAy2&0mf-pwDX5JyxB6vmo1$2qH0{O+f`z-wO={TCC92Ef|uX^pAJ-)HM< zVE!@(t)vcozeHlm3Ceysf(N6at*+rkc#HY?jG_-*@wmzy49XBs(af?3Nynptw0TW-obk`JTHX zDBfilt~ba;S>>OvJ?eVCRmK4l!n`G6qr0W0b6doH{x&)bky@w|peb7EnGPzPEbOWh zNkMq!M(y@It(};;vC)6F4W7J_tPa}ah8>ATiXctl0@i%PeDRB*-qdnySDd7}b%o?P_cg-t@QqpVI<$e~o4m~4( zoEi;#n|~F(FL3t`FKFv^p;>q#J6*p0sHwaN7_Bv9VeNn;i~)ZD zFijt(t9m9?(037O2|m7#7nm$a;czw`Ne-S+PA=7;ROvnqN}B%pPX9YHER=bvENHA1 z0Vf}IXoiO-sE}{nT?|G|vIyu}Ib4fXf%D>ZDsn6>;j$XZ{F4{ppo|L;{1mt$GB>zr z042nFIpN?NIpI&hd@-TQLG(N93ldjBez2QqbA}tDR^6YY(!H4F#xj>Sw;N#@@du{* zuLuJ(9zB6!N=e3u-WY2@*?Ak)xi0XP{NYK6@>J5$J4G!rON-D|<;ekJlU#!^BL&n= z94nwqYX@UtiQ{o$<7z!15%29ngdz_LH@pdP9E&OBz`?TQ6;7K0Q-2{UGzdnifLdB?0wTq6}ZY0}KDH69NY7exS>9z>=t14M+9@~>{rD(Cb}W}p)} zMaMF*_Skdf?Qs%zgDjty|9kn|(2mWHif$vOGZrkQc0G;YJi|eoHH}fR;%{6h#?f@R zTlh6J79L3h8k~c~j}Ue>hPW+ExYd92INim}_I*$72L>UUqfA5Fy~R$mRR6&m^(u{Q z9qY?%gyz(wIX=T4#i{B+00@1b5IPFK>9<3_J%VjJuKJHeoy`epI8ab_wGacgOYd2Z zw3o4VIlh>1W@2^4^1ovar3Q(nxiJBeF&u)9NmVm@BW7CLg92z)R$to3Ba6 z5u>%GK#bQ}P~yrDjYB0nn4A#Z)tW^_CH$D0b_;D9+*WmX)FI-SDx^f9gD*v-5bJ6R zbS-0{7$~i493s1H-;NX^z`O&b2^}mC19cF>$gi6vf;T9MpcxFLyy9%!_27ouf*+bM zhZw_=SWHcWS#muZP?-gS_Gsm31xZAjau*=8PYNq;L2rzYXv!C$dlg1-Db)ES!s8lmj2Y)>~Q$25c%Rt`KkRJTh2 zwd=Ox^*!5w>c?GkwDo=Tm$-%RM+YYFb*M=vaNWc(*ho3y72yPKMpevKukIa$nd*St zDHSM5@r=%%sDtyzB=?G@ax-WJ#`>}t7sY|1dRrCiTT{l@bCJUFkaQ}rKagQq`AN5c zDkeJiAjQ7`QBvu_C&4d0K*_BCnso+NAprQf(B4&cPTSXfkIlckmMgGel7J3_8V7zt zaxkJhA8E~yNc>>kDg2SLwB^e4VxF!h#_gB8unwRT%_49`Kbi5V?5&d8Db7!&W4cBn z#wG;!V+#&;kI2WYnPj-_DHK>`hle+!W( z0vWccT?hz`mE}cXP37BvLQ)2Fv-$V5kl5SHtHk&ep>C7O841*W#(Z)kQR!+w3~SQ@ z*Sr_~Pv$coq7jZ}+O-Lf2uk`C*Fvaz=|N(=b`LiCb}HieFy((Y;q0YirBPLBu&JI$ z1iE#3ag!Dn0`zU)Aa!)hjN!xL;owy56P4M(Hl8$RU(9a4!ufMmG6DyCJX@W`V9P|u z)`fVFhzaJtn zuMmak{i05$UiU6duLk)DGk1@r+?%++6m^enur-rF-+p^LzpPMfXsPadNyS=qhgaWNe1jd#|ARi2JT0KTpYt5KK7El&iP5x*rw0 z&^CMh9HL94k*ed+Q*R4Of&H3|P>*tfJb>MoJ;}*8(;cgcf5wj=2S@1+V;InZ=Hs8R z?EDkEpZJe9b9%Cthio)Px_?v!he`enI|gDzw@9U+PXnUyFK3IOeylZpz99$_lv?_s zd8wm?6pWUZHJS6YdAI!PTP^cD*HvSWcPO{vv7MLef@-Jlxzx?=@#C@8Olmx{j$`O5 z+2^1|X@G@dNYhFEZVb5{SJsa8gU7GF1Zu9;UE7%q?E1b@JvjKz>Gb&80UNl1qYz^x zTs&fY7A&VBsQ%YGcKh}~anoH{cv&!@+od{8*!-t0&zB*Lt2$Dg&!1>MmDX@hXUY5u zE09`(KlVEtH(Ai2fN+HcX`+zOjq8N_YKG5Qkr!bQV@8sdf1~XOE3?BG_9XI~- zok#~F?LT3{Clh+x;!HU0uO*W_kBjE6z8Umv!>H6n3=E$Zg;dv;PB54pkZiCz9Y&A4 zi0<4sBKg|YZXdfSDqzI4g_WtHu>|pp8l!-!>Yf(_#3?uF0Y|nNGBAe3hXeyBo(zOO z&o0hm+&!)5F`LQ73pFzxw_R%NoblX6LX-Q=S7rH7v)ILm&DbQAUtKSeiu_iW%j!aW zG8#7M4FWjDcn1bb?tvW$p@t2);^sSs8(7?h@mT!W)IJsgOe6IDZt}uV^_#x8=J+mS zb!3uE{8KwnWQbud^ujYPf78Lq&yx3OSZ?`1r<*>+Z`4`Me%j9g^!+<~vVZ4cV3dN= zHpU1-%+(dy@VM3c90F{bnB5fyWk<)S0^+ln4jiBpws7|${wJ?1Z47X;wQ-$Mpmq{# z-)%Gl=0qXYly6r6B@ky`s(u6I6l<9b_3JU=^<@E3x(eRYzcHNC_mGQ?u*5)r>2~v5 z6CX29^8jZ%k(<%x*d7~>a_v2+?VUt@nS$cxLW}-0W4)nuz^lk&nrxCrk~ZsvlnTx? zh3Zd$rHo%2gKYRhDIEaOI`N#BN{bS6g zb6xaRO4>cV0g56%u2OmIJ&d%lvMd!a%0El2+iWrIOu||Cyp0NTU8qo<_w!VfL1#ZlXf`_DsrJFNf znc04_JaS#L@XYXX!{`#{F#&GH1~3y@h}qNX0L>ou(M9y`{nyb*HC6tL#CYUmQU%=44O8R$MS=O1TxV`^yD(qlcE4I-tiMrGO< zzc8ZxaiJpyyL~pIgWLeE+WOe1#SBk>r2cq3;eh3fx;x}z>BxtV;-e5$_#XPEOxqlO z1hAtsH>Sfi+Z5p3Y|gI!_0J~RJ!OEok+i0h^zlAyRGdoV@!g5dm!5_Jc(jJ@G{LXL z9fzozVVv=|KA^lxws9{#kHz@_>o8;J4^5n`h4n=U!c6wuei?4t8qz4m{&awt=P!#) zkE5_THn(;J>nbg;svMEvFWJ!D;g6B(gp(0rf0S7um+Ky8Cr_H6w?=Q?IFNB}e)a12 zvl*ekIknZ$6y`8HmQ%*jqIdW@KMdzf5YLlRtC66nqgdB^MsK5zmVO6eb-KT*s9`oc znSC|&-G0vxJd*uAKGZ;V{oJi%s(_0fCmD@Thclk{`0d_J_C_6oc*? z*8cX$V$`E=90_A+fH8m3R5Fw+M?EYupJMh7zjp@MiH<(vLkQ=sj}ms1!J!DHs!ryP z)fCMXvzu=LB!7o@ET&+{^XDOvSS@OUmW3b|teDP?3hijvXYUKmN$Wyrd$}N%dEY-b zb|FR$(+j4(awopNAnuvl4gFWPgK5UiN4RBq)NFfRZ!j<6G}2A^(+?x9emh%sS&o{Nr@)l!spZ)Fx|s}PmZP}w0-0&J+PR3;YAf|ej4 zQHp#oq!Dvrnx28VMV9mV?!_m$sE>bb0o<~T8hTsE=g;Arg8&*U9eHYo?=XvwlfDsE z^wj9`Thhwxdr&p<4sZhoO%hRY&XaBUrgY!c&5(KmAxk z6+M@F7I;6kYT)i4aqd6z_$*id5;<55lSeA zLhTDFrb`J`AeLAT+zFFxzR+>cM^TVc0^^rrkbUWg!JHZb!M`K){7S z3ZRy28mE^z3623wK!kMI!N4k7mqf+qH$YSB2*W+de>Mh-T9dG^Qw6Sk&V5$wS&~DO z&ovcbe11qnD)9P{?UDh>GiA4nL_Tmpd)=Noiu2QW5`(^Wc7e8-7p6;|5MEtd{|^B1 zKn}kTx3N~l|Et?&w%G&xOB=uA_t&}k?0}wR*|+Y*5_30nf(%@{yGzVlduwlj`CEHy zKe$$pv_(QzK**_EB?W&G*U(;xPN8}Vi}MxJaC#$^tQdD$ecbZ z-hX@PqGkadZ+=)#7q@z)^V$S1?}bR}dM;6e9Vp;uu2FuO&HBA*+uHqgOEdbLMtLpmG85-WO+ zPS_sv2=&Yw2qlR``GL1%v1{1D85pw5ERPcr7CVxDv$2!x1(=2b2j z|E}i(y{y1153ZKHB4l=RC@T--IWG<+mve)x8*HA?9;QAvW!*YLfQc1>$wXdx1o6)O zweuOWZFFt+!?ztK*i5K$e%X*-t|;#gz^tf=-=ixL9#Y6(MKvG^)-Mm;mg)M=Va%Tz z?*I6T{N0&{td!7>8M-NKHc$LGnxJ8Dygfk@qKN80Z%Ht{ToE>J?QWt--TkPb2DiQ3 zC*I@c74;U}+nH6W$BAQXzDIs71M+-vamLnQCa_u2bb?F?X>&op^9q?0EN4#~G0~uo zxS{8}A3`JHvmf)BLR6>?dfAn41TfXUcFb-k)#d~(Q6Xnl+%{l(HhRZDGH^`S>eV{H zrsUPs4EVq27kU^;A%&y9n~4Il=x^`;M6Y9AD{wBT_v~l$H^exLcSUf-)yK0 zZ6XIZ8knCdrc>$mZh9?l8z|6)NiJOsY1NJl+3pnOKq2HyvNcK6H3+WEWND*MhquOet@-Ewfd8=`HY0n+{4jme4b$-P9Ct-}9#xbxF9sOW5ud+Yxy9Lna@SuL~4bQ*4j9>ux}R?Vbrz-K&Ws|JOSlK03^Lb^6-cXg~V8p&c@l&NKTx zzpm_Ol`cL?+r$K|gzvY7+S8$lN-;edmZyfYxS;E5 zIDTC*f4n09e}4tc6WaTGy#D?>Y)8fNR6Dw5{>b}y_@jp9W5x7baQVsXJbuIEqK(_5 z7Y8Ddkj2p;aNhdx6_2DH;N!Cx86@?{ebtb{<113}BIDum+sUXUxU(IK>5 z#XZu!{zqkz!9=iqd0>#a`k{Ig$WBmhAN04pgR7Z;sc+KDr`EqCg7k7nZf#`yO$7BI ztccobo)x;9`^G&D#_Ud?M> z$??NvQfv>Yi=KsVDS2V8$_pS}6e-}TQR;Nzx3o4?(Jm$i6|^NYQ1U>EuSH;+FlaBM zN(^{behw({Zjcxc!|F%?1^T8gr9sx>hk!=dzWb-vS+Kp!(C;>&U{D|YfEL*fd_Y(0V?|Qckc2#U~3G}0r>igK3>zR$d~;X@IlbI^#-kq zbdA0+=$4UIMVof|G*C00*Rd)2qO zYeHGHCn^W$-2Iw={dVlB*(P6cwy{;O!f-hDO|9SD3XC5kP4`9&9+Qv{&ug}?t%R30r&^Q z^-BXpkuQn&acy*M0E5w51+{UH-|iK4xnr_u<{V>E0jNix?xzM*gDm9u>s7FPXP91y z{4xn%I#3US>lX{qeu}natRE(vza(G(_ze?iV%8B|%g2i8r68R*9KL4tKb$etm_%%u z74hOuCUq8IHRJ*WB`sgL7DO^$p+K$U>@yqnP%1hX-BeH~^LfkX-yQ^qZ;AA&i}pk& z=Q9x}_8YWG-rA3=y#?lP?XCULTH6K8*g>2;FbrPsEp*Kfrq0Ebg3hH1m@qzn zZs4sA8LG;vxeBmtKyh)nN=_a$K}vz7M0m1`*2!9+$f()jv9BLQ z94dPqob__d{Q_4^a0Wk08`^!4+y@)qeGEj0z$sCJTnnmp4A4~MlvGSK}+z8 zyCR)Ev1ZP}c4hB;qWD>x1Zit7irBcuJ}gWgI_I_}fsVM`D||p*FcK3INm01t1p9{S z+JwkQrMBhKU$HI>j;*gn#h@O5NNvc8`$L+-&0{3#+B7P`aJo~QX+4GLXJG)upx=Mp z#`q3&Ot&WUc|Fw7naqmBa^S-TciG3Wpu_sbtLK~_jlr{e@a*rb?@xPFhG#7E^9DU6 z)FpMUf4BSFt=Hu9?-F%DAM5?T5bw%){@Z}>?=3qmIQ;;yDqda>sP_%&n#O&LVe=$+ zhqPnYA}`_R1sEaJk!&+p8Q(*Qy!uZqmSw# zquc>gqEfnEH<$gaw>d06{!7w*-z`hOz8InA zbz(9st=12}DY+uMkNrA_-4br9va&VE=?dH}Zbej~&0r-U^8m~+ecC{tt#&$2SQbiU z(7w)Ye|T<~_em}eF@)6^96nF94G;Dq4A%g_c_9t1tk37r&7g%yAef;%a1AO) z!Su>8K7U*pe3v%Hz^=s_ny!`oo9J0A9;k(XvD|4-9&8W1r*!q|;l;50%C!xup*}8X zOTzkY!gjA%?**5i@IA~Qci*jJ4D}>!=wUSexh0_7IX@cK`LKQJ`Z{JJTn8d(n-bbW zdJ+)Gfrb=Tn_2wdQcnm>C+q!J?gTghQWLVPTVJChxd^6LKrhYpNJfw*W~B9apcS@p zmeu{r;m~3m^Ct}swlu?Z!boE7`l?MJB0@PX*9Yy%h~<-znssr(%zKVSEr#jS6|;1uhy54UcM#zDU!o4p^xaV7 zKm8?vmINt@JnqdfKUr6AzrIf>2jKdJI5NO|4g#m2DyCC#zp04GrGXX+xcYX_HGfX%obf(J5)&fo8ajGuOvKMI z*Zi0L3`L7Tfv)4c(Ps9u7IclEKnqBT@4}#YB--tXeYUu~wI6MJ3(VizTl;~v?rZFu zIK(IxW@8f(SJRE^x)_jLO;&0f!d{7o=dPOCzXY&0HUbmpa>@TX=9v?k}6J zb^}+7`=z~9>j5~7{lzM0zO7oTxL5Odr&=1Ja9$PN9(Ic4ZRe$Zt&rA`uN%s{1Ipus z>xYEm8Tsjz{XIW9pV#5S5m4t-?Ue-+7VXU~Z91Z0nW)%Y8T9o^XH+(><5{SnZ?03| z5Y9zW93sqvV;l60r2Rb=_lehHgvuW#;LAs^{G5Dzx0@;&Z?JLvR)Q2=a> zRiZZLt(Mju2gC&V)3tlBW6lh$j~Ul5GOq6w`89lZ1@%a}MSfWw1)*J}@cPwZ2$uQ# z%jeo@7j06&8pQaX;FTc2T@!W(Q7wk$xgq`9mDX4HrI&HIr`k!B>3$O zE^6f!?_J+(c8v@FoL&pCN>9EFKVXipbgs}GNgnMYZ{033@=mp(Ip*6EofX;ON_jw|8@WkGTH@bm(NQhTR01scf=0MSvJ z6x+KHz#H~?F@LoBdxhJYoelE~@bbIKy{26ZE<3;7$6$Cq?-N_Jh}_YE6xbdnr^7T) zW>~LC>qY@aaUr_V2mE{lQ+)SK;-u9zJE8&_V<~a$Y!4&Z#`VIGF2m_zer_Y-6A3*X z2`gRD^h7Jb`64lXU3;Y5C9lf+XA5m0rErYtN_)3JKV07nrV}u~Fjd5ZLGu8X2QOAA!~|t=ZZZ_9zC& zHG@WUh_qI8JCc?J_BaCMbT#^6N3hZWz)=NJAxq56qZtI&D*|GX({NSaYTc_@QW_Pf z9ZZ~^g#L_{Ko#5SnQn*E)&u%s3;w&}he%X|TsLSN>gOG6=vDomL65_l!_aNoL5;!Z zmqNI`xC*z_;f-DvR;ku^=&H8qDm}mec#z3wR)ut}L}AGHtNgql2^}`}RVK7E4$WyV z3TE05lp&N?4$hIBh@JqH0zlCRkrWE(YJC5c&;aO^A=3ma#jS#Vi-*iU*)b_qwA~h` zj~R!zlaF7!a=Wpg+CM9{aaQSX0$FICGCodhhSds71rPd+N9PZM-4z_n5&ZzlSqD>heSVj$=WUImpR z&=viCRG$m-b-F|(kT{Mbzz5`WiDF?uAZpI(cddpUr-pD+0j}ud z9I8N*n}lN==5@mehT5QJ^vZE8bz4L7dDs(cGM+JAd|k26*4I51Lw4w+fC!8Kj{iSh z`G2WKibnLsO$8TjMdra;{98^vxfIoH+Fkjdck0^F-$AJfXg6Wg&Z7r_D^L~&=T!nYjr+# z>QofK6SX1K;D2lhz%-~E;(OM9N`&}b?{81&5*|&9zUieRoeB;gwOg!3#XVgs^iru$ z;dHY7Iv$i5wB3FZx+VsoShpPHjW%~L;g3S(lz}gxHLBO>|Ib&igeRcfg?m8!-;l4s zcJ#e6jbuojfpANRy*5Pf(xvspce*$PK5-vsB6o~|bhU0D*Rr6!n>xflT`8uPPAe0? zk-+n+_FgZAR0`ZCXx9dT>(s>f#O?3!-CD28=kuViX%6R?NN)Jq$muesitUctIxs+< zt;6Qu+K;!r1?F$=_K?bAc3vJkqOqI|^D#NL#}4k*BG2X;|MSw5+)NjHMW=je3UNDqq%^*L?s0$TKrN)7bfs7W1#wNk`&XvC#Fn@C~py8-i#000dXJiAutx6iJ$Md6%p997lu)|P-NXNT(>cH%J@Fk|tozgMfb2SWey zYatcjy1|xdRGOR{YwnA!*Uf_)Ig%%jw75B19yoEeeSLR=}Lj4{B%Wgi>m2qMa$ZQ zaxD${yEAN=2tVIa7wjU0otzIUfKRk*^1wK|En0A?+mevZ8}w3K#b40oumZG>LIA+A z>HjwmOc`YEtlrj z4E)b4fCH%-3n9p2hWxs@lKzVJ?uha*p&ar}Y${DKzr^X)e^w3pdi5lPboKjo$o=qq-j)nZ6X%=rS?f_p5byDpt_FoG!#j60gaY+i zkWL#WBh?}9NzZf>$RE#W%Y^!F#&*x=2;oav3$SEQVmi;*6E?9Hr%Oe$u)|XN#d~0s z&ejk1mZ_+I{g7Na+|fN#Lc5!=-Q}*JPK1MD`Q&zT(YGpi{hh(zO;_pmQ!$_Oxe<>4 zsbGDdu|8^t)B;pkhfEZ7yEM#C8x_wdhZcLQ^KjIF2dhKi6J4+@t<)2cMud|V<+yY| z>gkz*^>lI(I8WRXh170D7n>sn%7OQhFETV2){%5g=Zbuy0B3c5l9ugz8YuJ?Z=@!y zbSWs03(8%>`Y!e0Jdhm_cvV%<^3)SKcYhLY9u3$$I6jk-)Do@l>LR#&!K}(Y88e-B zS`qUIQ1cnEt99f90D5Mh8>Z*d_vGodL8}0wzOGu=&%j3dOv{RT9P4a$#eK`#71#r@ z6iLcG?TVsw9+B}f3tED1oE!V3hrzWZT-0v6*Pa|ae8VwjSz((%mFKZQ zKnB{PuYVKiCPYwJ=f%IZA8-2&rMI{C*52A%`wdP0>|gm8zO?=6e}8NL2ep6E9pW!= zto&cD$^Z79^+s2GYj5qhG<(}z{*P*J>(X0$YkziotC+vFxAp^TVb3)xu>q+apwJL- z5!eV~LovO1^*eaM0h0sJq3cN?5p_B2GT^NcgH?efX5||MaOh%76i|V4=(PCnryW$& zA;Fed1s0{iRoe_5xfr4|QKbl;BhVFrwHjLU%E#v$dMI-{RCT~0t&3&#e|HhA4pXkX zN>>>$YD>zh`V@jg&Y`qXk?U4!x`PbHy9x+o7FcnW>dMNigtBp{b+ee*#f?61Vi>Tw zJ_c_89zsuA8}ilRrCE?)joiDxxoeTBq0F0pOA4-w$7z>Z6=O52p&Cl@>Jvl0Fr zq`Id%2Fl=bejnkFA$;cJz{e9I)=pgjI)r+>L{?UQ<5{$UG>o8T$e0f| zhu7e`do{-N7OKrEF{@3M0+uUCm+DH~etk!2Ao@M18=tiyBF5*@fa_=J-^b6k+k`^U zVY*^@jET>le&r{p&~t=Ljb>L*96e`U00$O^tGrzqxf}8P+c%+0Z~Y8MnTA+ zR;Yh*+Rf|FTG#y8z1#hJ*jKANw13BO@93stP-)0#^0rNYc1H?C7v;QJQ(W9^SDn0B z6LWB=k7EI>;ysMc^zsV)$%~&++5H0*B)zQ=vhcXca|WBnF4V` zf&BKFqAJ;|m<=8FuNHen+#rSsr$0+`YQPN}!M`UQK+w?V#7&FuG!DqvdipaP?+uFJJGeC$y(0$!zc>Qdj&z-wO>IoY6XC@s%acVn^loefO{fX|)a z=qw_TZq}N<><@dsphX1oEh^1ov@U}fv;PZG|0MPdMTKnGig2s)Z@gnM-sF}-0Cr&!B+b`WYm+?$-GW?C-h^rv`Z6v@D#b7go*38RJhMJ8$j(`t2<+e`{~;2iEG{ z%mYLOu5lRdHdPeO(zPKu91HM`RLK*I;G`~zf+RbioxT|d|IE;#ZG@&Ok{@`MPl|F> zZ1;q8*F>0Jz8LbUVSXyGB)EK${g6klS(_*{M9UgNArA^n-=T9u%TWnqJU8H=UF}sW zZG)!Qg&eGh-9aq^)MfxEK9yFgu%^@61+?n@%;%}0(5$dYA+H;xRzjt#A=QF%Kf#nR z=j#`lur%=b^Tm4bD1PVwr~qrb182)FisLHt)5d$V%N5X-pMQS@%%Qvr*hJwwCOAA; z432E0Dt8Zl!iEaC(F>3(ZR75Ksa@=9dUY@HwNk)s-C*)an0X`}glg`$d`H9fNXT9O z4i3R?P%~H@-d&ikKJ0Lp-3E_BSh|`k>l+oBFO|YMu0UR#3rJgY#z8wIRE8GtnU-n2f@QXBT4`IAz^u{n4Swo(3EiD2o~xg_py_nR&ue| z4KgKQw(b?4F6{<-UhXrl@6)jUi{K**b~rD81VIOQ3L?nZgPu^B+E)6#86Fd zOS%bUBk3lkG3QoX5G;hm8jvp)hmV4MRjiNnX+9>w^e3N4S9mzOKptVM%|-rFF;XUC zEG1GHNR>cWx=t@VaMEqTg%Yo&!}de(Vffr@A5S-2R}aWze^!5n-sRC z4)t!C)SeKri^Nms#0t8~HM0?cj>_ogJALb%mAjih?x3V3h}rI zmeo1V*RKpx1?eKl=kK5Jb>o=ICn|^MvnOq`;QGbn`WfDri(qqw^&T)fw>NDgIP}5V zJ?HB&Idw_Va>i8!Z2`6i26HV_^?o{&OB{*Vy+V5z&vf4K`kQsjCS@@xMdoDAW3v$&)VZ>B`^)dOLRfm;f8gzzyt+0!9 z+ROevn0P>^5@-RIPt^lL-%BP2kITmmdZ}DjW(I`$d4tr3!`DpcT2@@YngCTuo1C8J zma5HqQpIRGotlO#qfX#}U z+)nJd(62oyFaeg5b75KileLYkdlJ|@kpsO})Vry3m$f!>5?zse_-iZLadJ=P3e1_~ zZ>tQ_Rh*~n{dSNpJS47gKR<_9)3D>i?hs#&+N(0ziUCRhYT}wA-mK+N8u+&gZLWP z(oocHlL8aRbvhRhpp?R90BkQr2rwxjjusL0gMW-iN#bjXV11WH;_0Qj$9wKB4;*8B z_I%kPPQ1w1mfYvHUJIsXc=_F_^N#a{$%!_jTWLkW+4{-i6aQ6#WqMx|FQ5{{FTv%O4ApzSR7weX|AE;Nqhw?cSnTOiY zrUkVC(|J@w=Z_l$*UEPa5xQHr#a$#<>paG$hJD}?>p!j7Oo6uOurS{t3qmda@b%hJ zB;_vAePnTKuQJ|IT@?9LG5KDC6Z*Wa$LuHuui|cr2n$a-?uGLpOg?0bL3r}b%zE)PYme>;9_XM9&6qCr`~@@!~6+2{F+FBa$sUTzcR_K zHLA_P!ygFRFQ(2}UmpbD{f$h)xuqe$B;*sT(b$0N2f_5h_Zk)FaumGWW#lgszWOI0 zV0YBfxPHjpDsg_Un4Su>OejariFM(AwLYQ?5_Uno(?}rHnH+Yl29yCZQgFQr_4etx z_P(l>@2Jg+%a;k)cM8k#J%;5YgZR5&QTL?WaV?T+H}-9B?Z?~R0`s@_)_#C30vV}< z$A!q%4Fot~SOFb(u@*E2Q4kpcPXr9f590yj3&mj%M9eEu0KYd?S70^+EJK!YPzcZ3 zv;pa2{hFbY46z=R_rrJ=Xk^5*+qHZycA@~9u$sCV@(B!dcfYrXzGH_j=aG`3pWra+cf@M+Cs;;VDy{aLjdJZ$R zWPu|Lvf@ZQ=GAi8KQ%%^d+z$DHW%&mr|~ zrd1#hY@UQWZ9J4m$2Blut`#U=1&$<$3RR@9KRMF-kL>3TN zO9GVLNHPN&D~o}?=!)ByVTET|&`g>5h_UMH6czCGMw=j@xS_n}KQYzO) zEldpccbj%=z4!H=E+G58)`o~zBu#V^%pVQ1`TIHy!Ot$5=2mHK8f#9#@wNC|i?yf; z1hn3g-M(i|=eR+r?CzD%v-`6L-s`<1)vke_8vkyA(ujF&=KLPqEiJG(5(qi?@mZ)&$GS0o)Ry-1Q*X-dEt=hLjr$X6TlnR~h3c!z=RIE7o=K z^Us&>dFHtkXf;%G3WlrQ=huol3)V-c8Yr+mI?8Vrq_fk4JPFnke~xV=>qlR545to> zZ+))DoNf~f8Ex@?Bmj*{_7{V!joU%fu_o`G3f|g}w!H=BZ|$x9z?zuRcNpLy{@^~U zlS8rv$fwGxXKAQ+c_^#8bqY%Bc2`mP0SJN9jNyY0Ae6s5x7rL^ibLHCp~Tk>vMy*# zf|iW!jy50HcZ#$E_ouBV3K|HN&94=}gze5fNPWXfFIQGyuXC?R1#Gk)G7nfNRFrLm zwGS?6M1bJ^c{Qyc5Kk*BFsgih5y*L`%I?pYPTs#B)U4126WMWc-vPM4Fb%H zbRN}yQ?D{daJ#l1JZ~Qs4_X1e5W*i2PPta72u!HfUia$QqClH43A(y$R6b>^tSn9= z@~RGB*0mAhxzSgb&y)H=QO+9$)pJ7IQVQWQQ0{~6;>QtpT@jvlXjhg?H#wzbZMxQtI{u2 zh3{(K%?3IH5%9Q2@KLbck^eZoHXL5pL0O1kaq=y?k`l1K%Y>D03m`A;{A80KF-s5>q!ba6e!Hq=OqpL#`Njh=^ypLwg>ZE(hH~)V6~*%16;c}Nabgg- z)sE26OX(<)!>5X}DC#nT0I32ML-V!IMBMHRgZm7R-F%p61rPrfDEEB+!$-sX%6mTj zEYYv|ka71*#o^nG<(DUf-J2MI+AzIVOh+bOmyd?&)$s6#7hHcbma2eDO_Q@_5^}eX78lJ6TzH=`ONP(0ku%p z+7nO9x7QIk$Goe%{jO4XL5#?<`HA~y5%=7#z6J$-#o#LF9*{wxMhceJNEia!Jt667 zGc2E`uJ6%iqRZ+egzsM)^0}cdipz%ty;GzV3GuQ15w5R2kx=eQ$4M_6q!^X!cfR&o z+YR;NhO2Cbdau}yL@wkLFh6s>in$Z?mEc$(zVop!L@C_xpUp6TTJiE%?(p)L0r_jM zcz0Ow=?~sBSbrz|GvxjQTNZks7pHVwxejdi2^)x}kWJ9e32mLQe5aT{@t(A>+FWN( z(5TPZ*gLb}^e?~1;g=_*fA%#F?-%HYjMGnv^piTd*Sp~Kdku$QDb?^3JdtipD3nn> zFGp%Xq-2oSI%q_oJ?Z+$qJ(aO?LPOQI$c`VlS!LFuhQKUn6Pjy2;YbDYwgyF+hZb1 z>8<^!+go7%*529=t;OcIt2#RX}gKmWXO|K2p$$8XU1-1gYCPGS;7FCv5 zNu+2I`uAch3>=IcRw-@xCwt%YN=PAmS!-iZlT){ClG@OYZlPv20=qnJcz>AFjh@ZD zs+E+7%Yb}))o*(7D$Pb)7aTo^n-%TDJ%3k)!Ep&rE|qu~Ji17i8Fb5d`P~`ha}MD& z9!v=DuMabDhYlHr3}5j!DeS6zie3F z>lZlhBQx+nQ(h>tEB=zRM&B?e(r0$Nm^(8bo`eOi<8vu2QFquR8qsD>yV6GsVU zae+1G$LD8y2b80sEe4y7)m9@!Q&+*m!@~FSeCd5o@AM6N0TW$W(elCs+*Ui!w9N_I zWA^!dWTiX{<|ihb%DY2{Z$}`TUN`8u5DI&om|TcLo+pJuM5$#8dRbP?p9<+VXJLwT5)_%U>0uU_%q2@b+5=zCkXNYF)65};potT}Z_kV$($PXrD+Jp)Re zkM6Cl=<9LVhNW(CSTQ+`#bh92+MHnvX*IeT=B)xxUTK_%U$s#O(S^8nox%JWwg*q( zi8;3%$S1@6%r#_wX;|+Sm)}h&_XDzh`H~gApdJhPz)YExX)8E1z0V zqH3{WGZtLts2Ym%lfS*7E=SZkQN$||qCbB$%+I%U6KoiW7BgrwTzi)hJs5H3uHWIwE;~+4v~BJcz6z$(fTNcqeZwzbI^@{|4}Vm<4JA}i z6DzRQ1Fw8x1@`rKGON;?dGgJ-Qlpo8Iu)QLq&sEeVosQ!Dzw=^ADG{`p9AJkOiFdj z#i|V4V<-pp<|8cz)yHh0b<&!VE_@GA;PlhXWP;zjR*wCALZ@8>dS!YcHLl!~YEzC0 zfAs&nM|oeNj~nv;e2?L5%MMWXg*JKx>-Hy*q2w}@UcOQ^X-qWColu&pUntC)jI1)w7pf#fAsAwFn?=r z?FZI62iZ5(4!?HpbOds}ifkCLc5{fEU+V_)4KPTLO(rpzj{{lqEPaRm0{t)wz4r6e_p+^GFz9Zv<-eWl9E@S$>){q!F`Pl zdw1XQoGJ{;cYzU60vKXAzL6pcLcodl+5EaTf__8-K+uGn>)uzm!y_X|2*_~uO=;}f%W<_Y?z0ku}kgpBt zVk0Ow4}#)GR2htxHY(+H9Qtgh%zmRH9%I~j#SD50DerJ-6@Oo?!-&NUP1XH;$%TbR z@CIPzwWTy*avg-7^zpu;#c|63f86t^%y;;#(;nze9zh)g6)C&3Vi9Oi9~_3sV4sj( zo3mG`twa2~N^sI~9UbdNC|%dXsAf}4lAiCuqivb`2VL_bs^ZmN0P&ju0RR9=L_t&- zYsL6#Hr5}%&$_6q$h)?J&zHW&Ii%Ty2}lKi+Pa51)vLXmJ+YL}r5}!a;L&(|4izLi_%@njz+>YUEsN*q(H#mgQ8@Bwiw6zq-@+j zfMqw9JYZ+l&jX4G02P>?8b#V%&@4Qp!aC&hXVIQs6nTI(p6reiJc`YF!gl_I{k`Lj40s{2sqf%Z!A zj`t#&{%4z*3~pIb?_8`g6516=zHUn~;2`~hEV2K$dxfcCYK;`86dZIu552Kn3qUw8 zw)?SG??u?85h1Y6icVJuT9ArE$E`mrX-I91Q3C?%-cc#>ytQ$^20GHLCrT^F4bcZ& zM*xm_bzwg(d?yAUu+1QzG-;DK3c}z0rx}M|2@c;#gHC4<^lE*} zqyLsqwJXxsMO|>s$9AExq1N#kJ}dj9B?jlPdzAY`s@&#D<{4bC8!$hOXV-N&1cZ3) z{y)G2>N`hD?dEv|rtSL)Qc#qfQvSwbi-`Duj@GUE5Fy-zuT`NnulBU4{6|pQ2oG(W^h81Qy(PtVml5_?8bme&pSVd>TNfUUNuuI&<8@yx80>IfQQ0$c|oB-D+=mQ71zP@J@jD2b~a1Atx| z1&ti$2m$JvDKK^+?PCORLUFWRi^@6_t_qDlPGHs{=Jh~P!E|N?+m49>VTp(Ta`Y0+Jlz1`~&;cBe%wuR^y zaj`sU6;_1r9q2-gQPHv_*d8mk zXV@X5xO+fH6&akWGXk)yxE41!T^B$TDY#c`Z}p5 zfi-6zw>hEQr7pf%4iV^wnz!^Mm=uF#LczCp`@w`>W$QokDtcW=k4Tq>>zAYlr3;3N z`-(o-u3t{>q!79#RPk3c&J__DNMDhyAx8oi=wr&#;9U1{o;Wtrx#IAhV0|Z$JHd9x zq)}Zk&`;hcZB`0C0**#1&@FYP@486uD*~Ou+ROV2BLNqcWyE;OigwJnez{tb zuzYMimy1c(nZiR*PU*4 zS*#~mA~w}`r%Y5P7DvQt|WHn5` zHk`jCy`n|M+(xjRI;Fr9SP9tPQ+O_2BT3I{xNeT9Ds(TAW~eQ}606|q`-T)lD&{bG zK2spBbgfw5&zuvpbV|cp`|-B7!2GSfwI5iM;2|pmoP6RzMM~TG5)0bn0qd6ss_O&p0^`|xa~OO@LfWF zQHaePv)77xKXobq2MdF6Cfnv75YN|&J=z06=SJ5>framt+~aTsU|+N(SiWO0ust%^ zfs!XVy}B>9F2LjBLRUVPlTdx$ktVWL)cb`M_G@8cr#8SXtn!&0_k6DG%PKt>3jr$2 z!1|D|-6_&$xceh=mszzV2fr<8e6I0bmV;n>;QR*Ag%$JjwIhK{0Ly~yo^x6&?VHkt z)#=E8q)TD-DluV`E(OgkBikI#34{94733>L@9I40GQru^tpb+7@^q2;dY9&C@H z(V&>u>Xp8Pj+&?jBtd;xusu+5dVNq<5)Xpu#NZ+Oy4GgF<%51En(1ociq0kP$Q-Zi zRkz{V9vnto1t0&FiE!VI0l{=8*SAfAcJMiyfal-K$QQ%>VmK5-a`cJmEe%6fCIuhe9lcFt_ZB}fb|{U z5yWu#n)7XWYMrB<*5NduSH7e9nGk&4tkZ__sX_0#_Fmtq!^suXsX?y|GN*C>E>L*m zFyZ%&1|+Y@m&3q9N1oC$Ex*dqIpxOtI(|cn8Q|l@E!x^dR8Z_Q<(NC_C7+3cn_svO zB)e|Q9>~?6^K!|YfX|n*L zkd}J#kEjX;_@UjBl@x}2t~ZDgTK*MG&+c^c_=aPDYj1)1TYGCiyq3sK?S9<>d8)fg z1>lDy9z=8n^s@3G70^h)#b<`+b|`?0$*sSsf#20`?&Nz=csNI06bxF;kW`Sie5>vn z8RKohzbp^I6N!Usht2bVl`h5ky~-fMMe6h_-Gev|hk!%&6tEU2bD`RHz~lq&=YdEB z^x}|eX+Tx&ko>*C4J)v4-lYqkMFlHh+saITL)*dJcJNBCL`MacKJEMx=_EWpe}`SW zFcIO8arm}=-KgGmE4&c4n^UJAh%1ttIv&xXj$ymh;$3)PW?o$mn0fomW=8@}te@Fn z`51}kj`!bD8wMWq9o8CsQ17PxyVOVU>O*nJt{<@Laq0oe{=jDrW2TjrqBhbgC`4x+ zanKP00;pkF(J7G`0Z$}P*5^m#T#(WT-;8JT>c18PF3yz>WJ|&j_1Xl`xHkTln!2O{J9U2#sIEP47wNq5PBQ%+2-O}CW3VF1F%rhSscL-km|iEdgt_( zMwsI}LD43nAhtWN{7x=*)%c-&=4Yb{xDSd5v&9W>H^yB5_f>ioJb1I` zpBXH(I-Xwz)2npv^H30vDq(eKdr#uF7<@A3cWonBHyLZ|zWKfYpi`}a7oAVdt>4C+ z2~X{`dXmtfPTqUm3I@b4b6>w+vWg)xKXx$C&MVlAtG(nJD7-N$dmu ze_ah(1m%u2l5#XyCQ@V%&*qr&v2OqhFh6mQ&M$=Z>&k?UxJr4xdXmk3&!ss8yD_QQ zlO1m5XQJqXHWG{B=HPwaVy_B4jqVl^>xk@vmG-d1 z?8D!aXh=guZJsDL7yNsGNse>{WHoZ$eNSp`amM>`rS>~d@`UE8bIW5LttMmKdQ!aG zzPa#TOVTL^K?h=0eT;)XW({2*K&$k`a=us>U*xk6^?X{(`I=OzOr2#|ThY313GPtb z-JQ0$yB4?N(xOF*yGwDm;#ORWyIXO0cMleV1i0Dv>~o*{bN)?MvgVxM`;Gx@XbI|^ zMUC>`n9RBU7TU%Nc|vUPLDg0g{-zx}srFH3V&#~2`g z*=Q-pV|duED75>)79_1c6R-&ZsRE!pwUf7mq`?^N){Ej=#B+yF9ZQAJpR-HkQ)M{5 z2-6N=3JBE5XGusZtJ@-B;yT(>z#ZD#OF+-p1(_il`~lcG=1w>fK}1)S)6X7M!g;5W z{eP+wcv5DeUi4D6O|F^Qy^4rqLmH>D@Tmh_2|I@i3}A}qQ8i_pStO3{R1ap0K1b*Y zSuMYC;uW7K0v@%>9@$x#;$6TiaUq6U!6m#4(yh<8=1*~F4d;Zo z{oRZ`I!q+W3tnd}0Iy%oYG0b>196{jhy=CyK-Q+Pu}+PnvN525`UCqyy^O%t zj%&neYVfZovR^Ry8@OR~sXW2g?|jS*#}@}x>m zr6@yBjI>PSx(HPTOQBk5$(DbQFLC{*A}Qrr2wRmx3q7Mlli8n)`DsSC1q)4MhVeqq;}C`g1P@tyynYyX`~yu zU_4N#7wfhfYNy3C2>QA`om;h_Vm2N$$Hj1ZCOXs1t?P|lV^JLsKM8G6wEVY0p?7X> zvDmgsL+&3XJ8CR65eglm3K&*QhSshZA8<3ms1F&8m^JcOX~zK0u+>+!Ck!l7`T5%; z0n=a7meCo62RXLwnMOjJM@Mzer^3h4?ePf_#wOfraV19`90v;1F>WPgewJypb!Cxl z>*N8{zKx5m{{a|b4jo=BxxkItRee;AYDWH}dLD>c;mXQ2PkqZ^nIY<>pcr_ri?&9` zXJ{wM{W^`wm>yf`4(W!^La4Tk>K0gD(~x|+t{1uH+V*D30e(Ea%dRclf= z$>Mi}D~@YmL_*gBfiLVYenTYK_>A=LF8&U$JDDa+SM-#U4r%y@97PoPwPH%-dqM#$ z8M(TY`^DlZJ`BkZP7h@ir42q-FZ>QTvlsmy-9O(-?9P56ZxWH6en0=$j%OaAK>mGC zarf64W%c3N=E8`th`$73u=yw@XEvWEjrn(t3`>18zr->$=kn27LrTz82;mLg5e~5T zMPE+=e!_2k)(xik!xTAq>F6(Fcm}DZj=`NAT!r{zLerkJ3O_`{%N{E($tUPI+3aZn zI<7j-&1k$Xd_DWMX?Agaby;S*GhH+AcGBx0eb5NXNoaEB_YJ_wvJ<{+Y zu@|gda=nJjL>(jl*y++l%GwIxwxl=ox#r-w&M@J7a8sE1vI&buPMyeETv6;IlMB!O zACzAb#a*(QH{#V>D4ClET;MrjBXzVuvg%*1j{+IIx**-Ci11M(LBb5@?1=Url)5dn z&p7|sL2ik-2`6NlLCr^8H=);|d3k(M>yygZHk-2|uwmNn3c9LGVy}w`oB;?-K$d$N zet&X^J={WjZHt5QFM1PFcEDj=Bvi*t2fTOwR(}r>3Vy;Jad7$mDo+s^`;EcuY$JJ& zXUWvmZ+gsKw5VvL8A*11J;&Aa>6xilsE^n?1cIiuaBu$VGe%wwHpf5{;&mQF(7>;Y zS!FhIQ&0(sY|{VfXV^|K1}VSik$!1^7k9M(Z@1@WBLw$6 zL6La*B+ck&=I10jA0pY>daA_0b2>2!Y86#Re z;{Iw_(Mh(%?_oR~6Nxvkc3bJ-RNk{`!n9jVN{gqU6O8%P*_HSD?&!#i6O77D_!#|m z?Q?EdzVc`d?B5X5GH>1at-dWK+3om} zXPmih)@KsD>7n;{u-{9}oA<-DCkD%u16G^Y@XE<+cjc4$c^*cqkSc=3YZ*nOdpf$4 zNfwDdd9)m5j}J>=5Q>AzLWs_6n8|){aL!_epX2-Atbefp1t3bP-n+Zs!R!37teiuv z2Mzre_=;SwDsLbB(sgm11Z5K1g-=gD`d>_a{3|EJhj__$@~MNs$Lzg>KULOzdl=dV z=y5CegQlLVUnw{J$9M01mQ(|d+%EXupQh&@g0AzL^)Gm<#em@ZoiQxRu2;uS7C#`> z-LxM7l8L17C?WIKxc%CYdwwT=91vmIF)-?g?(W_vf%W4}CTk2FJpI~1oIN!Sr}MN0 zyjnL__waptAlVE*X_$@`dw;(%eDA!x8(ep^&Jzpq73~T9Ail#39UX;lW81w)PlW~K zzD0UqpQLTii3UvffSk9LdLaU$jq@Up8_w6N_IdHi+n*oa8jqhbTp-g8Z_qF2S!CR5 zx<{yU8{V;}oOtGUA@A$ube9qg*ohNt}~iUo?AKXjhy_R~`bS-dhq= z9xuQSH4z{3N37nx!uuS@CLzRm>D#xMa!ICDfW#k98>a*A$Hi}sdGz!FcI)x60YPn# zOK-KyTP*(r^!#m%rlC`OhxipuySSn7DCTHvo;~`mNAcZIL`B@$dRu=a`~cQAP->@r zQ|lbov`R~;>W(WdjDYKAsA1WDWC$+X@lwa3gqrb^Web$ggoMg_`UVE*=|KN~$I_ot zuWK54CQdq^O$e$JuH3Atlo!b)DBM#pr>vMg2_xNp1#Oa6UoOvJL}^*k3^ z;h#vzwjvojMr2uyNKhAG`2z(4*HfGJdb^!h>E}3$Gx;zfo&Ui;Gw(IGB z(2Y<;igC+nqBNXyqhfg0bM-WCQzB>adVc!QPW%T-94HxDeDDvC?0Hw*a%!I|oWv;r z(_*8%J?{WuebY{9|HhjKb{qQEDdY)V?(P7$@LRGZIKral%rbQ_>In(~WDlald7v95 zH^|yH07l>2KKPdYSVd*69KDMMe}9E~_b@IFVV?DcR-}3=S-ZG2_94_j#!on58e-!X zCz^VUJIc7cxOh-oA_o4)Fw}fNAYH&SHkFowU%lo#!*tl-T44*HQ&W&-}-KSJu>GqGXgH20*1U+%w5kuj90x2~Z z^Q_v(>p%C%xSe8+(2j%R?^LE09JuxLmob^aUf?*pmMplL+7AR~c!Nb^uH9wlp~y4n zccrNg*g{{hjad8Lxo5c6&=1XMzP;>xrqh*)0N9B6CEHoHUh50u%PYu#;sF$XqyXk` z9KTI943v*g2X%-MD04z7#E4I6$RG7<0qbyi<=b~hijR?k^nktyz_Y9KC%x#~L`XE+KjK#KYg7Np9${t3MkPdg))hWLWN2CxSc`;5P7( z!5xrP<70+uxb5<;tUDD1`RDYc@mB=q+$YY$rjdCbzla9&^gcyiB~ccalN9=-o5xtzV@oleD3>G}p92Yi5cYctA7c*e&zEcgb@7pCEc+Cr4%&Y8<)}&_< zT!fK)6wHgTQ*!ovc@*UYg5POxRUwP%Bz+$@*@&pQ48y?LWQ-6 zaWFuQV1@TaW{>m|*E?J{J(_igC*<1$BX35zA2DWkcD;*f#YW+T)@>4bCzbH|*huA6 zM|uj5;33D|Oawk+rV)wx3vouHG~jPJ@6H~tXP(4oS{Qt|gEPSSQg*yyequ}pGs%*q zFMDv6KRH&e74dS_{;FfR;YK@a?lL|9p9Aw!7YXn7d()P;9~9fT;P#stGX-yPO~RIx zznd%7OO>cT>MbH3DeZ8u><5a?kq}#UqDB;#M2R4@*hP+yazJZB)RdbTJ_+Yuhe^Rk zyhW-N6cdEs10#lHt^<`K&oNS)sYMoKk3O3QDnrvvygDC)HeaDvr$)7;f}wNAqzE-Q zVTV6rwndTp1Pn!B;s-#+JejcW#J}-u6y>LL2dzz$%&mfC3)td<zG=Mu6sO$pET+8{4}>Ln`$bXzR)U|L8ODL9(i|QUAj@77 zuZu>6%F%SxE*)1NWqj3@9ZTR!(I-J8>X9ufDbvqK9>I*CymGwdS153nJhB^}VA)jh zpR``QXO=ZnIRvdR4rt`;dW~NrZ#fgA}A5U0zg8nn{9C2gJ zi#0y@r-lW~zM(lc21?lvlJq`D>YjEj;aR(%Lo8u}%ehL7&`}Hk+MO$DtjX?GP6pE) z3@Q~ghlL`SXPW4~bS^Fm14u1~ydaoe4qu-ID_DVke9wk$c>vor;l6JJaCl6V=AEa{ivub_8#hSuE-c>fr{H9RZ=DC}JYsp)4+UMmld)*!LS0ra* zS>`ztj%@z}jH8D#g)9xs(b;)rEo05$jPserQA+`5Fyh=*;H9zCv(j*AmgRBsCodvk z9mRnxyhl9ZOsZXD`}a%eUg&@6M3!HvYt%^lsNnKYtHfE3#tttZOpW39q7GhM#15wsA{Ckqwu^q7S^4Br*hrYMarq_=Y>ADZGj6EVG3lI@{*4k6esBh!+<4Uv zUQmHH=P<4-;4h2TJ`R3&{nR_;fy1IkWLoy5P$xjm_XrY9`30h*K)%}YBT2Q6qDbX{ zS*fhmXLj!_HonO3*A8lLgPi&(27hPKY_Lh;KEQeOpfqA4{t0{CQbhPE}iN2S*@PZtw7 z@SN%oY>&pM8n?cy8genAp|xQix>8i7ELD2&Vo^Fi5@{4I1vU-`QhAPVnO`;111~0r zsaw(NGTpd`vc`mV?&j^?cx$N;#b#%T^&)%4Rs3@h+Z@Dgz-)5q}UFyfC#fuH)y?u2Daabobt zKk%^?stVcon>TN%*S#uOIEYDHk8-bJ*5E!nB>$`FVyhR$s7P{o41O{WYqRrt!BR$4 z8|w%Dy43J9$L^Ibls|q@-;eoe?PD8#N#O>4W9GSm>W=n(Xq19h^CZ@7Y+;ZwF-JTu zE@mo{3(L4>m|&g(mUw%;7Y|{}M`1|e&LQ~Y(n!$NDZ~k34L0Q^{3#l333ydNs&-|* z3rH(3{BfEFpuMhOuJaubZ=(2RZT-n_d~vxNd1Bt?a^Ka-s~V}-C>n;ytLJ+@Lm_7w z?3MN@at-6+%HL)yLtjnX9i6;&9OqU(*zwqoaob4ArTtDR~3*I8{ z_~SHJycBDW`<9%pJ+GC7Nk*3DF`%wbiu;2|n?EeHgie(st(Yilp!?MEs+&&Y@k11U zzV@pDNpBSrIek@^J>Vj7m}-38sZ|5Su=6QeRZEq3+eEevS)Q{C+C`4d=~f%BH=E&8 zd=N+OT+RjQl6~q*l}-!m+zKLmvSy~`HDWcX-mVme#|a||yu~{9e6yhlxkI6f(H0xJ z-sU12djIXoI@gg8)zypxTfxu<$N#dq-N=IJ78W~9F$mpPZ6h{lP<~7Og>%5v_HH}- z9E=r+KPZiVRrdKxK+D{HAN0fJ!8TDBSETGJNPU*$&w_StADobDj&RBrCT zgnHjws3v&iwnUOw*9vHEjqdQhlJ-R7p2gTjsi^KTYO+e^b1-&X;65I8aC07uzxh=?{UQRbn-ZfM{1WUlvX>efAux z7xc?FQ&W+)2B+fuo>wg9-C;?nhFL~r`!w?Y^QupyBTJro^x_kOU^Y*Z0VPl$!7CFw#pF4t%^^7~%0hs+6#~fRH ziMOo$Lq0yjQuvdMPng2EUf#2i?XXP;ukNZ!oGrFBXza}_SeQa2vTqO`ogeZ%w>tw4 zfI3~iRRLY{Lhd{&YnkmC4;IycmJ1z!w+@!8g+9QXjQ$SPK3_}lCC@U3#)h3BMOJ#= z5xx(iJW{qNP6y{m`CEJw<-4~v5}d)VBq7zE!s2{8yP4e}^y{k1;N_6~CJCci*psp1 zzFi@f-O{@yzwLGEczB6UT2D}?jEphj+#qg}eUduD#w2N=PHtjCu>q39xZUToim$=^0)}R_@D7{?a{v*b6(IM^bsW-d4T_MjVX2}ABAnbuIOBr~uH6PeV z18WrFEKH^HA&V;YU&~>K8{H2PKt^7TUmmB2W-XB%wlSfqvZd$4lH=I2;wH?bG)i$a z(j-Ezr$v$^nhiEJJn^~d_=(-sKIQC92^louf_u350fWlC&_0|OaIW0S5BGIv7t2Cb z4r}4=pWq&y$*>Qm`ah7mkog}D$i`FU0>bN2yeI>qs_|!utol5{+iEy*O)X6iSyOR# zH^w)HH_X~%+|_s2-sghdXCKlrqi}+Uk=s~tv83*P7cEJB1CIvzr$q)-+$_ z4wORpYLsl;ipiaDbv!6`XUEXKTnf z^dCB6&SjZ3ES?fN5&05EJ|oZG#CpAH$GBci>h^KJZCbz2dXLx)+$2n+x*t9Ae#g`y?nWs#)&AfGrqgyf38M(2j3d>;3 zPWc5BgUXqgml|c9reK`?S*mc%V`yDa@pgbK$FYUZ?_B5o+amu~(5-z<%t}U|K$#R0 z@Lk46^eH5-T_7HgqrZ&6u`Wh5GK%eG^6wg)JzB+R)JHxiTqOA&fpdR?m87WLGpboWJb8Edq&Y!M44hndEFk2ogAG zsqFuO$VftV8jmo4Vrj`{xu_}wDD;+>X3YRfEs@Qp?E{7h9CK8$|Kb9nO)P~X6$R9q z*7(0&6pBiLUzDRVo%5E@f;`0+JpNi`jhM_WF5@B7k$!hHln}j`pn0UYXZ80GfPbDE zIuF&hLm@|^yb7wvCO>bTAUn5l8*hkxu^)$3kp2Q+7_%S0Z!Y+0x5*dD&=~*NUQ$$H zJETXd<$KYbz7H6yKlmvH6tmaT1&Jap@E<>EM?CtZ;G-Er;Vm&Wh!P0Na z^=3XD3V)RBhD=WldAm?AF~q?#RY=gke5EzGi)o%60I3K$vgNT9vozN|;^=%DsE^DR z`_5CHLhW3FdN4cPyx(AR^JVkXSvkqsEG{9<#b&>9a*%vqE4b()tc+czU`+ zcTn`e9zdt5zW)b2H&oq1nI_SCtn-sxrxGbBJet-Bt+NwAD8=!O8|88k47t3{OW{-NegNSO=azQsFziQyJ%kaJ$2VR4V05x>q z_?HYzUTP2J-d`(z#pT!d&Ns5R7WuCLQhy^-3FVRR~0-ZxSYl85xSAUdAlsv~T~K1=e&ABWQ`Xw{m5!CR^}YD_(z7@YKk{78Db)pJ~b$omjb2 zFfzrq+g75$yhnZiU9&-Gz5&GVV}}(tVJ!ia6Fc1;TN|$LXq$tmRQcZ0Rm_&H{HlI4 zPMUXxsJYPRFjuV7?c76Pxv?gyXZMBCxaP&khkdu)^YUeccn~K82UciTrwykSd`Nsu zbDDG=icZ%OrsFCet^MMW`?||=?dW!dM>qN6EL;~P1^6*+K+wh^0amV1812Kd{YC10 zrjH^rDbDG)S3!NK#s*zo>;Bjlx1D_Ti$P-tb=^u_$Rl3l13V|B z^L7Ip=<}L=uD>JVFdl_hLvBx-9-gqdyrJgLma3M<1is4_O27Zd=X~}Qe|x~U&-8f^ z!t7S3ZcH&vE@Tfi{*CC|8b95&{a*!5s-~Z>}%h_t-Tg zwhR5S&BP&tE+M(BNAV>CYU7C!MXQVb&_h79_#)piGV0NVldOa>5=(!5A%nyg%eU{T zm9O`h485+ludhd+DwFM}LTxQ082RR)+e>167I7VkHZawT#bxT{G;(mImcbDwHXa3?QH$ZSG`{SpH2+lW6p$_{L!J(m;WVBU z@Nr7~bQY)T5Q*==j&XVzb)b*ttDMe+g z2Fagg>WXECux~*%n7d+XO~eXiihj&9sgWdEp0)EMtoQW-+bg&h1}@ee5^M$5{g49* zyG~lS(JIP4IP>;HsHWCKTU9l`5!pE;7}qX!+N2u8I`~NYrk&|XmDN;BiF0JZYjS{c zJ>$_v**mi+xUilB7p@s{_L*3FB}gFz^hyNmbQCvCH?37OrXZBV{4QBj0#H!6yDo+& zNyy_c0#X?fivys7l6sfxpu=)%BmL6#6k6?`V^ysv4z%NJBDn0*ZE)CPAf(^65XI@0 zS-Wogm9rNjjjBM$_9q<{G?<;s6u2CRD@ml@JRG`YDRMfGoA~BGJBYu6pX1mq#T5Ej z^xdsHfDR#Jupae<4HED(v0m{ksnM5JP48r4HZ)=X407M-ElzOW6O`bZ!&Jlg(o{z+ z7Jpzy$Gn#9tx-pdPDAAJxAqj4Z5sbP#C_4;^KfawTU)gC*rSKT@8XYA2Y!0=w-lIV zu%hvE7?|*%`WNS{R@{4ACz0ZAMvEd#>GlK?4aPpu<_;oRPxVYwfn`mi+aISKEvehC zX`G%OGvS8)wT#ZL1^@R`4K*yS_4g~2oLL4@N9f%JO?=0B!C=b2V8IXVUs~d@e;o8o zPX`sl{E&($Z^?{&2IYvezXmDx5_LTL3Z>1r3t$;hr2I&T@* z4Q(%NF!N%lU`ko>Lacj3-#f-(FaB)Ut(;*@nlwK(x0aCC%(1u3FtnS6F=A4^Z^UrQ z^l=J~)9Kr3N;;{~aK5gQ|9k;-3Yf9>-%4fGB0V*G^1$U8Mim!kb64=0Brj})S6Gzi zuPB~-s+~Uwj9e*(u@PS58~k%;LEk_XL5|{QorXF>eNwTyNov9d*&-=j5fPE3J8vWMkwnc1WiYuina9V{U(G zjSOm6n!d`J5+w}S+^2gUmg_pika{=zQY`*EpwUy8fsTXab+;;W0Vr-qD#WHGjgyfP zN(f_#saE|(#4wqjAfxaKyB`mDh7~RNh2jQfNRJdSf7>U{IAZERrzQ7P$Ja)eC^45O zos!W51M(~}z+E$?mf;FJWJ~*{u&t;{?TAU@YTL6ijlbAqcmAZlz_J5G#%?llOnr9<8{Vn*_YE#mwMBXGRXFo*DLTf4zxgD}?PQmO(UaS|uk>%WS-N3QN3uV>Q zdF4w@uV1({6xh+#30jiVOhi3AdMM2u+wpT@U*%E#lMUO(Wp4i|>hplA(~2yQq4zN# ziSUoo6sL+PpC%Q|hI-Lcha;XxAv?*4>RrBd2kwGE?3e}K9e&v-R)6K}kDjOaDx}!k z$ZSZrAB z=d&ccM*bM%tT9Gs*p2>?~4xby*&VRM2IEyK`?MGCgk z)yg-ljfs~&|Dq^Q5vD(c`K+Zr+Ihq`g86@h8kwn`FbB5D$tt3|4qT)J2_rylpw+>O zfEE=cxNeHG8J|NBo$z6aZ~`NW{6)mdsDr3}qtsRsHQrj++uRPB-_Z|E^x)~nuVqV@ z5^V$&c>SoHm=W#7P%GJH=gS(*Y*uev_A|WEEUu{j6UXfxDz10wH05bY7nB}=Xt{C! zQ|qH3))e~u9U?ANfaO6{ZG6VR^IbGqhw#N`bw<0x3M5sr9YD2Acqw`U%3q122o*@F zKji;$OMd8b*{qA*Yd9;yHZNHFF&L~MltKcdNP?sbI#6)?EASV)Ao@&~j?&gc>_nkH zhl_asc$z=tL#UkjGvSP+K)0>Jrx)v}?_SRl>c&hsJ{ETgQQHQzjljJWxVk0~r z2(?DXALQh#2qt}h+3BU8`m!tWTdK_Mdg!HRdM{Of%K#opgsO`6XQ?IL=$b^091k=q z>p2vCcIT^-RXpzuJDjJp%;2;s|*U9ZN*_#)XkDw}^qaH_v?jz4f|w{w7ouF!KSufcRr;(+%)Lot(+o7y9n_ z@#QO}&@t^lDbrq-qa&4x zf7r`iBHG)rs$l5L; zC(JN4iU4NeScSsUl!uHylW$I}^vwOiq_^HHh;3nSW z86bg19UC}cQDlC)_fdT@)sFt#Q-+VYetPHuMVni}WwPC}pN!iCn*17k@iiPzK-EF)~FJeQk~v-?_XZcT?3JEZJ%PZHf~EYs0r9BLJkR z=WRYG)r{JO*HQ~zKlRi7VkL${mo9AA#R};$N{9cMx4T0}`TjT&cnS(Wd6O5 zpI^bBjD~P39ar-O1;pQGO*$M@1AB){8+fPNMk$XHt7Yil|B{HPJdIz#@BieKzjynY zt?D5tlwVG)hA{F2Q6fC`*s|BAf+10@Bu5z10dreLjeCVcUXPG5Pk^;gYtI?T{jNmrY!u0tn7&}R+))4m_d!0ZL1<<=* zp*D4SBRlRRr5c45B^cAJW`MbXF&Sb?f)5r%VKeV5lU)2c z;SM$H(s*bF+@wwi7XHFmcR}#{B#F(4TFsOpIB>ZPZd`{ka8#G-;C&z zw5BaqO__$^eLkT}oDUf;qXTOfpyL6}m#awMXIB=u&3)^#OKLD(jFxNSIJe2u`z_Z` zjC+=V9D($^$TZ^!;F*(f8OGse@VKs~TtJThpHapkSKCcip@-D=iwhJxFenp_Hvcvi12>L)qn4|8Wt@|?J{Cl+zs9+SG6?7g%SN3bpiX_@}R4Y z9|uJb^S!26*)+E+sq!Yw=0fTkt)8shoP0^JkAF3^2@F+KALpqQJ1RSo<4Co`c=RwB z)u6Q!AIpdzWZ97@*Ct-T9$ESG+GDVDQ@uad-il1*L2FiZ-KG7Idvni6neVp_IGvCf z?Q>s%_7U20f-{x&&Re=L>5q7nWdT5c0&}&r_BT~udvK;sZYjp0|K8Vs$v8&W3&+0x z?1n%RBi1p$E1I&?xod)SsJ``oIQM#XE=SaDAJ*3XEcit<#q{RCzmW^L+b5B#s@#W& zlSo+nBzpW#I`g&1U5mt8=7`jUyT#~E(O&CsryzNuu^A)6A@#Q5WlFZ`(0%8PlP{kK zvaO&l8>%yBmV2w^CXCI0KIv&++_=TufdgSs+K29Y7~0AIxPpms5K^En2;_b zI3&T<@s(*!@v&Lm&VAK_Xv%n}%KT173+jYxBSjf*KA$zE+Rx&AF6!QFdToWYmPd?g z2>_cu-jBN^a}yfBiQqyT&D2C$5=^{SSnSE>I&fN%@Pw~f!|H1==fPv#BjGS3<>#M6 z3)^hYEv|;m&+pRo%I|$-tE&VX%-1whczlTkt;)OLK-n>OURi;`9@i!)t z{Q{4_WP5(;v1;Un^@EW|wL$;kz)}V1a>Os&a-`mA$rBP}3x7~sP0Or`K8_mmk=q-j zH)kVfT1N#XLh%6A_$b#QW>RA0k2Tem@AWNVnlSf+-Yd@(# z8-I!M`AmZ~y3?H3-OoPpmJQ~vl%mn!!y@pYLZtdd!I%I+WU8n%FB6-Rw87nFLg0V} zkn0qts})l-eOW3o@xoUu!p=RRvK zIluvY>62P}(|&rFE@X$+&$hlNYqI&BLa8mQaC83_FIwuDKe+;ygw-sm*+@_!coPS{ zbA$~4CYv~aJHAl9A{`kMYiUz9=njWpgGd*){7__KZ=BqJJT>x zoGP}!7_D;z^}l@rIO7~t4os0(OxcPqKMKYc3np*&K5tQjWK899S(oGvg*MQ~NAh|3 z_j;#EbN(=%po~Ca{7e{bgIdc3Fx!qf9jcr&F%G8CTs#^IX zGf~_lK9?vV#R*3Qo?$ai8}QXciyo8>>;GY3IE0L|ovU!HUS94vEu}5WpaSfSBi%ns z=WD=*w}aIv|AkCrMuqR9@66a~NeMbKVcp3OKM9M&HK9R%^SM}id_moe_2({)lLwqq zQSX%8zOp2;jERJ7yEb9U#PT5h-6C?hN7d&pmaSpLC8lr^y4O*ZYF`j-{#IEv=8a7O zc{oBD67=CRK_6dcmAT8EvhI1wtyr>5X!aS2w9W(N_UZO|xeWx;MI(9X*20qFIx;ig z3UD*==|JXW?V9e%{pN08+NQPp9m#XfJtZJN% zt%g8;{SZTLKR?-Vxd%ClXPBU2(_o|Qa9jlvDii$Vfs*sWG9l^??77c!gx}>f-2^qc zGp@no9D!-5`E58ICKlcWbq1Lc-d?>M0M}xfb|;fRIZWH+d3i6ESvV1ijGblYX2R)@ z9+h`vi>#2%qdFb=FK~YxaxXY2dVThc;>sCcZ_DpRq?Cd==JHlUdEMqlQMT_EzF>eT zv@#uwf2AP)kh}RNK5+Zb8=D*@6I=3oX^bBUX6k6c7Y@YY_HrNhgEkqEzX*AY3vBdWKVO~xW>MSoJ zfHDX`70Y*ST6K_H=S`|JpqGO9BG4e}vhuJmIo^XYnAa*LqTK3mS@;8m0I>enW6djQ zmtB?hxB9;m+xEoS?eCy3k3JEO=h%Mj3sdm~gwd5iETjE=HtH?n(F~fkK{dHP!o$UsG znC;i8sW<2(oi4hym`n$kbWYDf3C644Zy0o8DzmUx*{^2y{c9U`J=NOqT+uNkFlbS=dsY1^J>;Zpl>sp5& z(P$Zc7fmViu$!;Lq@gKz7g5Md=@Q(YD4*L)wR5fU1aG_l`s~JKTgv6i&5|!>fc&9e z^0yEEPya#~%M)cios>LbHN(k*5p!`D!O<@~KXzA;(Mr!)7FO9A*M;%s-00n?t1;#p zYr|l6Ck`upGQ!XJ4BFfE-3j4cxZ4n|aT=w97cR7YIDb}Xm~yoX4`(RqvPB@*O?0;O zgS|idK3Ds$0}_0tyE%k0SdG!5^0Kl zuR5OrJJv1Rn{y!PI|H++vv0WdV^M z#fOogazsI61`CT*Uji?w3l2+YIpo_UYcUNFN$}1IKLuA1a1f$|7OAQ(WXN;G5L8^8 ziJ#+v6f9^M2^77rFKkaw`}7C>g1C zlKO+**UyV!LRH+K$FO@($fg1K%Hztx-`h`Y>0c4D#D~$>#_9Df%) zV=2+M5>X7`xm5G)W@sMlNiW*cN9t~({Qlp04>fPZw+Q;Ar9f&}>f*skDL<(l+4+#W zR^>7#In9>GHWsxZnMyKAzn?GM5wV+|;X-b!IDz&abyp^zyB&R$6Hq7e$^tn$#HFHU z|BMP4)_;Iin4&SOfiWCJ$TiJ(?r?~5SCCTv&bgKf|6Sd1`zM@H?hKYoUlF>)vGHp5 zKeT`uC1fLz1LDr-pdsp@*}P`7sg2yJt$#ZuP*D^eyX`rkjR28bwv_WBF?#eDqXi6% z0qx-0AY9dOdL1RLJ$Ncal?>4R5gP;9Z-prp&IayoT&2(5BM@!Ngv@EaX|pUgU~3SU z@2SMS;A2;cLzBg)-Mw|GD>aZ{2bWsI^a(ue%rC$a%TSbH@%&|Y;LkE;1135H-D}Qh z@k%MJP0}>f8x-5X+|6;pol}58%7+vK9K_mLyg;9gxMN2@ss5Ht&UFX$CyBJPcc(Rk;~qUd+$W%wn+U9w5DTmd$2xMjO;!sjpTh8`i($UY z)haY}McrU{uUX8IL&A8UD-{eX5JMGi$qhMpyJ^!;PB(1N#ZU*DixG8M$yVoAepK1` z_%TU9WL8taAEYl>OrbF29u%P0qP}V%yb6EzvlYoR%Vqf)+ok(<;vm{9VKZc8kY~ch zvGJwe2>YOK*z-t2X2s=dV9Msz{OBF{3P$Jm)$N!<$|J48=*ur8Yt=bx@_d-s{#nH- zVbpu#a62a9hein($_jS~bHY-_x_jB>NV{4P=v7!vHkwn77UGPk@E_dUeMT`^NLl*SWuY-Rq7V&|rlJ-(|>z_F8U@1EOLqDy{5as6vJPl@GZN&mOK z&Ks9s1m{6~W-l9J^WQ0WBfFPF!$S#*213l#=tJ)+z9`3NGUtFf96p;}IbrWNe%TF# znV<|B@L&^^uBW}{D_+BF23nPeJEU7fg|_r-1nr9cswezIL0T-TY+vD5_l=N5X4oJL z9$zH_kX{NS>7R1h2BGAf|9768R|4FY#e|Au(rs&57bze#4h8jjmT@0Lv}M-5vNQ=4 zP~f-M-x^{a{A~Vu($}U_oX$EHVWF#mRmqSe`#lILNA`u?iIyD;xA|qEa>*^T9ejLm zBlXB#idNZus^RUtdu=b#J;V3iZ-fQyQmJgOW7CI6is3|1E8^woOyc<=4*$3jR>Q0H z-!M?IG!|f|qmwA2H+tL;XB^`4m;<+^fraDx=^K8F7VhnSkqH=Sau_bV?fR?#)=!4R zPgjkACw;1>0ueSoSjSg2gVA146P%0n&R%`52L99$Z|>h1Nc z69lx>)p~BW(gYA;U`X2AZz`gmE3YHrE6K7-i`_>Y0tSqU+smJa-!_1)u|ADtx&WJf zPEkrq&~Rlzlh)tUr4%w)TKfvJ^K7xM{*fX=3rSBlQiAv?FDU0eqI_6h!NLZFPDyE_ zHiZ7VqPlu2$TAOQjS(`sO1+!4Xmf23$Mga7+9|ad8fft1PkYGB;rH!@{|ECx48Pt{ z{XSiHeDT&GFz7n`z(d$8IKEWiUtuYs-RBV?H}|U#pKPT|0+6~uW6Vu+k+{K870ks( zHC~ko2oL`1adMS9s=T;Qtq zpxOsGp95pecW-v*Z^sz0#Dj8-q4_yf*QGlfuph~fP3MaFX(h@;72AhHM=-E@=+#QM zcIrW$Cu?rh+eNT`U`cTLG}O55tE10#irTeV@$$QL6i8PF4J`xLF9plDhU3RZVML({ z_xx0lF4YD6SY=)xxc*6D04D}K{ghtVZSmWwo_xf3@6s4Rwk+6=fPRtCWo5hb?>I*+6G^3;V7oseY{^U={c!<~zghtW*2k&$>Ghp-wej_*41Q0)v-Bj=@tcPE zrQ-0b3(Eb3>z5NQzt4Yv|39CRONCu3HWyPo|3v$lpzR`;8u~eB!}^XEY10b@0q_5$ zA)lD|Up@{|)A^}l{`LaB7Hs+Gx)9ux$}$fG+5Jd1Ojn}E0Jw#kVSS)At8O8Zx=RK% zbA60mK}EQi?S&J?MSVLuU}xj`)_$DrFC;K8rQm<~AN~jYy}$SO@b~}z-^c&>KmL#S z`0*p|@9*)~|N39Yzx8kZTlf$DgZ}`3^{@WbztC&^w)X2^{~CYeZ~P5>^UXH^fWP&( z{uch5|K`8>Ge7tD{@&li-}yU#2mjz7`~!UZ?YH>Z&whq~+PH39s8#NLQ~C zIQ*0M5rK?vMw?e`Lm=gD>Y`KOxt&jy-n(8Mp;EV^{%nD|nr+wvMF1qVG3%~^v?|gS zBa<9(HWReTaQUE^pBoP6UDebTeW%xk>6uyUu%{^p(8{ImJgE!S-6bnQ2mwv@YH07P z(x9gmQVDktWp4ApRHCoCDBjpm`!g=tt=d?@M3e4a4HZ}wpb4vwZYQOe0xDno>CmhE z$O>DAwGjaKKlf^8V<1!Rre4)6M|Gui9xmorib>^Dbx(KNBSq4pzMK8R7!}*BgfM$G zOB$#)+i#)`HQAg1Bw#DRlu_RuarvDi)tX$@_eU`s+h?FayyeRAzY;^`*QCQT;46H zOTzVoTQTKTV!;4fq7~S7FDQ4?6C45t^yL7wV|F@5 zn78v@Y|dzzqJLTqvbAo-SdQ8gI?4T}nP@=YE2J9IMvBGWxq;si=m_lzsOhD0&O7yp z2`wL++2PpYB74OktD~F3O+bY}flI|Cf}?~LpLj5iJ`Q3{C`Tsxj*beN&aPNq-QV7m zT9I%F@AR&$UJQCRrw0huM}ZcnNSv9NPiyPzT}O)f_)OclHo!#Ajgq;)i#h?<53v>k zn9vhqL{jnHYT;)?JT@E%IwHzEQSHHIRGzhkuwjKt4^S{h-fA}~v0bgP+ z1Is5HqH&Fm9M|`P`I(RsA&JFH)xeEdbecG;m3^iG1T4-ch42!$=)VU z5Z7JO&gY-0&v|c_aDz@$x1AdZFODa@a=!?71WQKO0q@6lcni#b?CmckF#nr>^KarG z{iA>My`O*j^a=m)AO1u9!+-b>@n8Sf|26*3-}yWETYu|s{e@lQx3&NHKmLzpZ(z<{vrPE-~GGzZ~xo>7XQV6@n7IS`A`0n|5IG!t^L58IixEp zA=k9oG;ZYqd;}I8WOPGu`&PvSQ|tPl7$e{btD;dGfc1K;1RaEgMoqvyL@q|sc(`U z@@Eb6)9@-rROa>w0}p6)t30D>R6zY16K>(+00YkgRwpM04edZ8Uj#0}vu3|bPiR0H*3jrJdTp>Sf+T!=j)y((s;Ruwwr}hoy!g=@@ z2j*@?=Wz2#?D2=_{9y*He1CP~0YAp9u9Z;eBt4l~?g*>i?ij=n>Kwtjz>>iVJV0bc zE5B|)X=umX6C7bNDO-i5$rA|Dt9QYv*9ue}<3}q4<$R_RyJb2y@Nf>=g?Zo=&&aBv z^dPupu8H{)bOf${WhVM0s%+u`YYHxM64XQL&J<$iaPzSSb$UZ2DC3=I1XJHf(gZxe z9;vXcu}3Hqu|%F=1m=x@X7G~9PgjAec1?k{Bs5n!&llSMZTG1|hWoVHtm{d{dKiJ2 ztRulAyL=eq+uhtV+9q1|pxhzitqpE*^cA0djIl^UcIS%HfNRC{j1GaejE=a8KJE!6 z-6ax&N(1zuyk()2L_?>|NGN?rpzq0&x^VnTWkox#$3!7+s5(rVVRt_UE2QqkJB?@6 zS+G759n*l$MQ;Ai(LT8Pkhl za$Y@A1-mh@HnfzwR)=^pcAwDi7HHAGe$N1Zx7-tja{e;m{1b8N%CKj%O!{0T$#j>{ zh=7|q2XOmFIv2!qN3wo@R_V`O8zJyP3H0$7eeu?Q-0d$UFn@Y_f~w-*{5Sti{Cof2 zzlVSQU;o$f^Pm45pFVxUfA`=0clgi$^Zy**eDe+d{eS=8$4`IyQ~cZi_P_lXa*f~A z{`>#_zsKMGyMGtI|NFm>fBH}V>7VN}|K)%AU-n@5-}!g`9sKRT{kQSg{@P!|KmN!6 z82{OS_MhSJ|NXy@|MWloPx1S||NHoN|J{H02YrpV_J4w=g!@I4sFqLK18bY~M#Ss} z8j9T^%0dLqv*OC^Zv>M0c_nUM&UZHLd zdG`JF{L`6-<$}%&ROeU^F)JW^nz6e!Mf5yibiQJ}U(gPThuS5viu;+hd!4SFf4 zcMJ-;hqSrS&qRBoayPR70n1!Iu`lwO^nr3ex$sTn!E0g#(6aPuZRfbo$^a6;^t1xo z2p(g+-uQcn5y}oAoi}U`M_hgiY=8ZXwkdELoR*ql-CGG2eaU^_B! zSUxG{=h_dlFp4a3uAm=QBhgbA!gXay&~v#74j|IK-s|GXfkc?|5PhO0lwNBW%Zf^M zB*4h|-sO|h&S-eQMobB9$tZUjZPxBBEyb8b67oOA$5_12(5Dz{1`!~sGzO@pL6g9$ zqWZ!2@T)WQv_Vf7)c5yj$Bgy;KyM@u!1YqmTy!dVKwb~IuQ3#p6Tk)NtTLF8tq%CH z61u$IN43f+@XatiZ%jJmiF0KV2Ihuc@Mx&ZgmO$M4++~bEQ#oKOaV6QRk(n#)Bl|Q z?Q(TXy=i7*W3Am{vNvO*D+1~e<_f-bUC7goiYUhvq2-ztZJK+voJj>%5Vwbna<6#( zONw;iJ)VEcL;v;t2t*Ix#Akr@kwH_oNJODmJJ@%gI+EvX|s0QBm9bJ#S4m(-UNT3_-z z4xegANEDFBpIhZ$_1h)9|e%Ke1xA#)yq_dPT% zXs^~Lb?R53W*X9E%q>$F_VW|ARKxPAV)+Q58K$R|sGMU)xlcn}%-?M}s=wo{!>3<< zZ>Fv2A$uY^#v%J9UEA=}R*(kbFzPltt>*?lhc2Ku#x(aNT0qV&el~_Cpk1U-sL)BhNwq?;Iy%HiZ3^&lcB6oOS0P*m;P+H0-v@?Pegw9{B6}kp`F7&U{m#F2Ha zr!~Gt+ zcShun_n^C(3rvwy!&sEs%y;i8Ti5w{^MN(l<+BYI-q*MAC+EV-><6M4MuGp<34Z=YS5e39>X2i zy1-$m2nU58d($XzaN11_htfLr3~Vd1c3<;K8eiA~Yg0@HJ)&(<>s>6MU>0B^gfQrzEiq&IHoQ8`2^&?84`gQ5Jj@`(@U%VVJ z-d|xl^SFGkpAiEfXMO#eb-sc1YZKDOvu3GC4C-oYZS?b&fhO$#`|aK|@@ zcQF))uDvG885E&1@!jJm^AE3!!r6>6=pK(PF*i4aXTB$all{&p6{Z;=iB2VX#llk! zqsS=UbMO5&Ff!v`LeF-I3anX_U#|kaOy@=x-hbR9Tuzp3beW~Ei&)q<#jIxfH&La0v zrOOo$jOWx)$?MbS>@o{TES_6YQmF|e@6*i}0O_3rzVr)T!cYIq=VSA+fOr4Mo_j~{ zk<76~a6(TZvTsoc0ovYV+67Cbgdb|VCtguv;gGec;9893$AaBEBYyPneKT&yXKsA1 zYegQxDgFpC| zJ;v?$+!$uTbNY|l$t}i17K2*Pd|bO8c7QVCO`;&$A!$dgv}-W6a$4m` zgKAo*+*I(PNtsLRq#Cr`l&ni6B%H~H1+_9;$ZRNFlh$)*%R1#QF|f1%id@t=z~KGS z`=Z=wvoj)hnu36aOgK^A23qoNb5u%MK=1)LyH`Lx1h|8TAA~{8p`fXk$J4HGb&j0- z=w=wT@~!=lTcA|}nrf~EWx1!awn2jax zd96bXX;B&szRmsUQTxa_sT7T+s=C?0H3e?%9-C;^$#pr=bKz&wngy%zPGF$Do)ZgG zk%;eqx8$rA5bhEOTZ}7TtT73rg&}1vSjV(A1b<=g0M>n zHxmn{M;0lb-7Jn&w+skGu#(Kw)LH?}CU#O9c}mE_*3&8Yrq+9!(w$qDkI zs%`5mbmkkaVDY|LI$d}}Zs>E;<4NT{J#7WYyQG>(s^}k2*gVYW9|^iE&YdG~Z0##6A-#MgBHUxEy(%xgHWo{EzK z(Qs+aLV*=Ms$;A&p0R*FsapY{bL1(+!tJ;n|H)L@zx>O;y#4(XpZLVDO2qBcImW;G zSN{s%^F7~#J9qBjumAPG{waUQ5B$In006%53%?M*={NnRXMX1EzV7R=TCH$A9`TR< z(Lci1fBo0LC694CJ~xJ>bq>ZmEn3HF{N0_l>iZR#aH`LwWNJUEzhrIz*~I9QPB0 zlSMbL37+(epj(q#3py=moHl%^rZxZF542gCw&A35&qR?5>-MtFkpWD1Q#G+tzGYJN z?QKN8=rC<*?Xr4(f*(CnPsMgxH38F^zNFWILCll^Soc-~8mGxk(PVkbSo(3-pf*R^ zRS0`l!2#OG`O729S%(rmI|<1_ibwx&fIm!-!-yIwBGdekH36>ztUf-Wt~{nYJr2)B zR1d6PPv|a3_{#$m9kX>hCZNpT^3_uaDX%<+yN+JAd#lc)sja6K)sm%9WXcA4cffGR zH$fUdRQP>Hyh<9Jcuhw1cNVJuk_uJUV}QRJv7QP8R_l7&_vGAA0c|d6LRmVG)#C&| zd5q^XSG~KU_*_0;0j377JpZzejk+;y?RNs!zs&nB`vKdR10X&2&pVV381D+=6|XO^ zpv4KnbmkyA!e4eePYXGc>Z_bqOvY#bb{2vtM#cnfysL9MRjN>%GP+2+#tKb{O~6jk z0?n!qU?4u0R#>t5nOA|`zGIqiYOX+JkSNNbuDz#K;Q~qF#!P`h)i$V}hyp23LsaK( zbrZlU^qYPf_S-&RDBNaADttu_ZWh8D=j2W@J85a{XIQ2RaXGzLO!^Z_&u+76OPJdF zcyWqUiF>LbcTW=1*0a;9Ny6&&iN~Ml%PwG{!JyPmlWhR-D&Uyck!Ya6HEfnkZeXY1 z&L^*93P4csN#=akw{& zX97TXU9f&gC`4X)?B3b6=iNUkOvaD7LDWr{%`^qtp5_4w{BA4G&x+$(5F3Ho0X0x$ z&b-NuR`UG68C$`uM31VmkBONkMZ!pB5^n$XM<5=Eq z{_S&k;SmcWX&ssxJv7#GN42n%`T0~wZ+O6~y{k0T8t;#^IWV2g#qj>IqJXYPzB|sS zIuEG6#bL2;-;THC_)nIYzw*i}?eBN)-1)2?Bc+5t`bYmLa?bcmf9Wsbo$q|-r~Dm1 z{^LIm0Qk+n`8U7mXZpU!SAOMJ;$QrWe}RAfumAO1_87P0b7N3Fw=f_#wc4m0bF~r@ zRne_uMcCz;Lux!rwe?EdpdBS{_HHb2$BD4&PCa?GqcxrRxf`M}_q5gH6$ThoKA&N| z;lKc(zhVd3ALqo5P-_aEyM+&I=>@d{{ZT!f7trJ3Zp7g^wM^@PxC72UA?ThYgqy5f zbU_w0==jaMI&`~&u*-azr;50@&O4fNd=-I|pgi2tf^SI$4nWw+%o_yQ0k_{QMps+ueB-Gw$6@qJD5ClH-$8T%c%wCsrNun=&4t$JkuzU;81G-oP(6Y&iMiS z-KTL@4as1w3pB3gcsD2yw&2Bol~8(m(VB8~^KJGHG9}dBVZ7U8xa*0?P`;_lfEzZ5 zS3wiwg7vEtfQV@=n9c>O#|7PWfuB6Bnbv}FE66b*ukY}4s#yS#quU*r{Ed@Sfj9Dy ztNKN|MVD^5zFNn5s_KbMICkqUcNE+r^mi7@bH|C#eHCV;OK{CoyFuFJDK&S!&$SCE z8pO$zA%_uO3jkHsoR<(=L&}(#V=WduJ4FvDx<+*@BzkuHt%L6jIa20MpY2l%nhW<3 z?Hpn5SlhF$k#=H!Oj?MUH60{ZgrT4u<~0NX`X?E2m*B5P0IL>|SEsHL1@LLn`NyI@ z>E`2gl0fRpe^*+Bg>|!2Nu> z2&h3A>^)tqDW~gpspO9-!_|s-L*&44&xF`iVLg+-4$S*bTCpQ(>f7vqFGNJ`J1oIT z1qducju*5z%)Rc_8I7*c>;BcOryNj^v+$T3t&nCmfKQ=C7S~)o?cw}T7Et3dbL5kQ zh|qp<^vG({Xz!7RY|wXVQ`YyKSE4@Z(}sJvp+4L|Dp8JvJ0G4u$M_W&r~!}!-2c!X zwR0HHBjPSm_|4Eus9Nk5RMktU!D;dIP7twZ7Q5 z`P&rX8_J`$Vi+n&q3IlxO6^#OLs4aN^*~=7-}VE}mwLiMw<0NeQL)6*?zxSb-efI%GmgH>A>*7Y}w(A)9$9-kE``=>Jg!9Vy10D$}V@8j3~x?lHM zJ;q=CtA7MN5@dh7%-}~P8Nk3~p|GA(0IV@@WZ}-_MpxDc5I?5avyGfJANfY#3nzt-riz*0}RC#&Gs#?6{rE9e}N((Zo<4Z2- z3sI^K+x0cYSXI2Y`)WaD^MO~WV^g%RmVoHJRW70h`?EUr9K2V9 z&lz7In!J=n@&!#=jMHxC*)st#%OOIn%|94OTMFEy#`|Phe4#N?;E`NSwo%txT?S?+`jYxlW9${YPai+Bbf)nsdV zUzdqcE1Kzd^1GLC;N|Zw{(k}8=W+B{%cRTZHcpRW+|{SAr*+Y*2{hRs-cvu2+Tq4@ z0#`SPtZ_e=^d5QYomX|=w0qlN*{Pi9LU6B|X)L*CXRaN?pHhNa(Zeojc@CNgnb=et zW!^XD^FvE&pwy%s*`|6aodN;wbr>XB;|suc0pPso{I#h zb+ey2@A$`Mc95IkmKN14Dwau$v{ra*_YJ4T1!vD;vBvb>QzGAArM+wU?^&(R4lfG! zFA9#&OHzqxlUP%$FFJpieCxdG_zubXPAuJwc53sZ7*%d= z2(;r*wZ$S%-x1+ZnqC3v0}FSLr!pc*Wfs-UmWec=Uq0S&`|o0}V)pP#>_j`69C$B!Ss>Cc`#dGaYA z=XTtV+i^Q?$L+Wsx8ru)j@xlNZpWuSe$5l}4}IuE_@;0ACIG+}e8Css&;R*9|5-i8 zANyl}49DXU-~7$rjIa2LulTgSXSdt6zpqxSPx{&QdfooMOo-nq$M{r+sTSUj|FlC2 zt;^8hldPWmV{W1)H7p=()|n_3Qq_Y~tH$AGIu(oy4*8;2o_0a*=5B6@)_Df{OLDbV zmj$^KOdHyZm>=h|8`~6XRhfCZ6Y=;<0^ak%kK(64{BCqFM{GZ?m2?NJp0EmCMUd6n zYxhov;a_7OK7vcLbY{aFo;mQi)SHp#T8%GslKg5ho;1pSb)dUasuZ-JDA#ei_w9^}ovs$r~s(!*~-70#&&Rx{f z&D?K5EBq6M%Bo1CM3_+6Nr%t4p+Xt`BphWK3}!2WbS#d z=rb;}inE=cbv^+_ND!Ydh4dYlE4%zIgqMFCc z9_}U}Uh`R`E!{5o<+PhZ1y-*M!hz>JU37$XC$5F+b^ly@l<0`A%2XGxCT@km4y>tW zSI#kekK`5UC%H${8p%B$P#z7cPCjq-z|y3&H*!g8F6G7+>0A^(qlp(^JGF!j2<~U40nU- zn+Rd!BhV$<#zmnhUg^+iA*euq!@VI#L3TVxv%;&6oo0Xtr>DE@E&*Af_g-IVRpvRa zP3dTYx;||}(}^(K#p&E@C%q!xOuBwTL%g+V=7j6M0N$u977OS( zM`s-S*&{m>t8Tjp=~@oSoxzxwK{_}~XWh?|=mbX|w<|Nig) zwE5+q&N2S>-~QY9;UE5Cyyrdd!C(A~fAP~k-z5}W-bB&)bLAMf<8x@#%7n!rXBI$} z0;q3mQEnXog{3>jl?$jPvU+tdl*&!;%v6DSd?@eJUXYApBmrS$Fg%`7WJs!@yH=>_ zq{*B??F6%UPypV!zQRZE-N$}%*t`@_^)2Z~4eGV9Kmjg7)SR!VgG0O)^p~Znt~Oul zp(6Lv5@GW1pwLRf?g1d|=3vGWm3Dje{#g=ki8ude`8fvm1_zw|#On!Mc~_lp zu^nmGcA_TTp!)MQo28Y(lux|1^?pBd%8CHNA)WWgYmf2V6MEd^rZ2e%4OL9lT` zdTZSB#j_VJ{Kv5Yd6h`(MpNu}xk3&s6rJ!e-CSgF zD2q=U z|87yF&;nTF%R4AOSlWAGw)mP8b3hZqu{LdnCFHrmeHT=R>a`FTJ*M-BwB^D4u^?U< zeW9MrOE+m!z7#X86$0KzNx!4blpj&IR#CSfB{5X+AVp6@}fy&4p>8 z&T8mb!mDe$UMsB8iVlr3(BcezX1U{Y9`4MXdT+||jRI!HXwG#v&Kf6#k#k?J4iG=j zweE((hII>+PEbVJd(xohQqlH$yWZxIq1p~cRa!njTMu5v4^7p-Q6s9(o#p$wR-lOL z_V99Zr%?EDzIQVX&7QyATmF}E5KgEYB|6lCM*k~CTFe41f|R5jbhVnyaIN`qJKnzI z*DNu=yu8E*KJWp2{ojw@@>_n(XYClTyz&bE?4SL!0D$lLp6|hSyZyA! z`Rweh{rzw_eA3S@f4=;^x5_a-mGS7&qc{E8lP6DpMSlD3_zVqwLD);x{D+}01M4yY z-1KwrfnGaWL7EzGI27~`59;eWCqJg7YA}-?lBnYFDaN6 z_L&OJ+L6w>o48cbKd$)Uk9-N9zjuv$UwFXPhu=X96HTbaSqGCZC_e(LhXVJ?8vUb+ z?j|?y&)i8XB$(o`o8}Iibv9AalJ>CEYZV}`*kz-4sdCrW(gK&T&k)p^7p$YIwT`JX zm(Ihw$EBmHbJ*t=eAXZ=h71Yu#=(z{3Hg-iAsigaDqy_ZV?1YPHf=4sbC@vC;q0;v^Ym*9^H?&<(}?hNTHvWr>gfV%`CWn7bCd8!!EIKw$Z zh6EG-s?jfgXSS2FAyWprfbsqshZorKo4Xu*h9#&FVJg7&k^D`db@42Cm#H8=$%t1@ zEolPM#;f`*=D;&o_<{4UX&)RiJI&6)jTxKQ5{?fd`T5&L5kfhK(-|O{{M(hEt?}Y6 zBOKTbv5v4=6Jh|9S`o-tXO6e2{jXIJ?vR-5D1uH zI2Hzu3BWSpcjU6?Gb&k^-Z5yb^+XpS+>A|oqO8Ijc*G?x5{AYPj&MUEg2X!3slu0v zn&p(sXrJkZvrHidFAgLl8Cmz@4 zpQ4AFRaEpq1)_Q}`ytQD-DaaEfTS5|u(WckwQ}!p?D&s&g6>nUi7JMDp~z(Oq89aX z<~>R4g^DZclkT<+F@%*tVtEf9Xp|JFmx3F?@-;mMob&Q zlJus-;`D!?p$V}RLTp8Bp!s4?2(9Si_o*duCoUg~E+~uQmrE5`bULePmz22(W{-pO zlymUvwKK$>Lx~l;ufM|X@fzJr5$o5aeHOv%x^UVZ&nQ9xI|`GciRDS*JzI9u4PjS} z!>^hEMNJ0mv(~*m-Vc~ADz3h$V)dHC`n8I9mEeb>>r40PtAr9Fj#@B}`_htjfbS?w zyw|oKRu3mFlzSX?zPkj33Fvk_CIHk2u^p$y0a03~eDyfDHO*r)(GEjJcdgH%P+P?; zPOYd`t)@~H(V>W!>C88m7?=3@vJNaz+g{O}4CedGzhFKt0JA5pT9oiZg(!!gHgo1i zgI44~t}LY8=H+ku@oSQp?{+(U?bm)Se&Q#70wRL%{oe1zH+;i4d{&R~7yiOuz~je{ z@%3N-_4wciKlrOU@8_O-uKj(f0ROD<>Z`8;pfdV0A%3eI<5L;;?%n&eK7TttJEN{6 z(l$0v+g3qc1n=>h0jhP^40>t;JPm%?`MGiq0HTm*d)X)iQc^{CIicpEUc|3GK1UfnF4R{PGA9GpWswYYmvcor?u%B=D{@Dx9#hWk zt|qvNb~?wqj)jFq)2oT@^mEW<0clc|++se$`WD^1Ch9X>XT^4CrQ3wwfF>dZC(Sy? zO&W|i0g3=lkj{I!F(d4<3P(9i_tu!s1Jc^zaG&B%C8E8Uhr4R6bOgHVI*Yg+EO5x$ zJ#tO`HC~PsLb6AzaAm(6A*JH*;;JQGNfmC#I|1=Jqq~}#%5bwO3l2Wd$tHqYxmj1+ zfkhtcrrXeB(R4v2_1w>0mFk#i__3mYGytifZhDk;fT=0FfgbSHIn>@a$ZiSJtn0$Q zVA{}@CU*{QU?SLEj_tYAL!NLz=o;xC2X!Y9)JSNrzwwZXfvFUFDes^2O-QS|u86yW z?(x8+cFGvuaYoqV0)66xV}U`f4XYLe%r=d56g@o)R*!k^h}Q}Pr@=Gk4p=G>uVRAd zE2dXrFUD2R{<2FzQ|hljfEIm8PwIO#z8;WQ z73D1BfBywPga5JnVqCuZK&=C5-wEr~JKC}hcV{L1<+Cuvlp7WWf@QI};-niL_O*4m zd9RriUi?zQ;lAL>Zyr$}uV^2+<2)GecSJpn^jYt&9M+L@YTCHg6p&g^I@MMLu1hzA z%A`E*Se&Z@9G@dKEba^GT)m)Z(Wg1POa@0+XuZ=016(_g^}~t6eYL`ESXidzoxZd6 zy%u++-4{O;xI{!+>IM7f16ENQm7@B&m~GUCMz3I9fY+?Tk>i*z}XaKMw%-hyU;& z{)+JL@B6;*!}opP_W_`&+#mWwe+U5Z?svZ%=jZ3RzP@h9d$aM;kA4&Y@c#F||K$7L zD#y4TpF6{BeGoPA#GG`@9V|`Ait^-yKFZYzJ8(;@=oQV6;0&u<{r>(>BJ}}%ORs zG>BiovdyMT8uh~Qcf4zg*wxXM-U=pubPz8y2VFZiCl*izJXUbcLP|0qSx`eoQwsJ# z?yD;G6H01bBsT&skq+R;1PtRG>uAVb1M7^H|i-vY( zOL0WRXN8S=chb>?aBbJ>ASi%x-`NTEt$PcRnR1cK>ARp&Kq}{VE$~Fj^JmK2h6CaB znaL6S+$l2M26Gi4wFa#aWC??P)-({pp){*8H_k;fLsqnfY{C4Z^Jn*o&$-U`#R?Cl zwnbI-xinb2p^#v6KxeVhftGVUX-9Z+rrOE)Je6-7}MO@Aaad1C>^ z@!nK@mn`lz98lqimIe_kY2%u8V_mF4fXR26gjQ#DQ3wE9VX}6{W1qR|qWj*{-N!0u z=!7HqcA6{upQ*B&+my|A*ODnWm z0pY}Hq1^}FmkniOx4C1HI_^Ah8R<7J^EH}Ux>QHXR$=$Im^(nS=QATXoSJ}C0rJ|l zd*P-E7<^slvAMr2DG?T9ES1k^#}qapY6g6)^PXyG!#qv5H^?WMa0yS15C#7Tn z=E3esV`=CynLpnOL%Ls)VyM3E-XQEy{Ro>&r76faikZelxf3`yU;FKN`;O0QVm?h1 zzTq3b0sriu{WAc-U;fK~8GrIm{>fkSWBkXAullO5!jJsOkKkYa%YXT%pBaXs`HcU@ z-}oEfvd6d`pBp1v2TbASu5%Qhx*FB<)x?Z6ps-+HIagH#>F%oitnrEg7%xxE`fEt7 z>%$jcfm6tuc`W-OqkmLTT}19QXbJ4J(9% zL%h?%imt(7wh>|i?zld!crj&m#HWP1il|-SHFNA!cOWp**LKc%1!MLFL<`j?$^J6&){MDyj{8cnpX>fsLBYeyB29ru-S8bf-ieKa3}_KDixv$) zB$XBd{Gq}PR_LYur9TSr$m8{2dKb2NeqLN>Xx;hUyA-*x2fCYr?n*t=b?)N0{%ic$&U4$TskNFgn7wzbB4AgMMD z3Q46E@~|BbG4yY9f*Asoor;O5jCR0Ya70jH{u`p1d zw3{mAi_78#V9L?x9J?aD5yOG3B2reNmI8EF6OaL~FQME6IXZ-aFl!TQv8rzg3$A0G ztKpWw8_dyF%%63FhyS_9@%e)1f89g$Q-I4J|HDVW1k)ixo42ISfFpsOygRqWNVnG9YL-rB=j8N0hKuM1n&tEDQh|pc*e&6{B+irZcZp3XkrR z@ZNAJNNb1G3vS-uH=f@1rHr^QC{f@C4Z56z3IB^Q;I^^ zeY+RDLFTE;f&;veb9hY1>!{sx3krGvP#DnGE}%rupw9uRcl5EJsIKh}gicE;vrwFN z9N|@e;g}%X(2`R(l4A>fmM#_D8$71-&9q$;eZso zcJ7TvluR+-p=zQx3nXgiTm;ks;Qy~aagF|Az-AS&f7gn|OcgZ@hm7Nc*!I3~Ais6> zI3WxUQa#cdFi}kk8x}r;k;N8MBySX!3`|>c;=3#EyQmdmH^B`Kc@uPAp;2F!-rrnw zM6t9r?F7TUfa5)CiHsG}*uHV0NM+HaC_)9h zD*Tb>S3Lzj{ZQZ!8RmaZF0;dU9uarx4f_p~LyzO#4yC6a!OiD6qK&R9wl9m$U0F~` z6cwb%48fuUYKSOBnb@9hVrosWQ7IMtAMWYmE2gbO7z*MQi>Ng?q*ZL(=I%zd367Su zvzSsM5f%Lv*XnS`x6bo)PN;v00o^r=w%uiIMGd1QIMW5G?BK&QA*ZOK!*JI%>Xvoc z=@-uLXF;0_@9KR(_hpv||NUL89~I=a5JXi0h(~u*vHjSA4h@k=u&U3iife_Mv=WSG z(vWcG72Yb`!gDv87HXw~#|7WV+&ch2X~EAZZ-vi_s5cMOOQ@du8evas2-DC3w3w;; ziXSS%O-6WpKsoDL^T8ZID3qy1=3U070^yoesj?1=K0%ucq(YeP!~{Qh_#t4LTq}C9 z__w5Xu}Eo1#oT+Ot#1WPThF)S?L9s#iFvIRfA|moVf_8S|Mvj^fBH}VX?*8*e&?_0 zF~0bVzxY%B?EU-q-_%O&5Bz~YfN%fyZ^!lZHNNFrz6C$@LqBxlg?>C9@onGsZ2*Ax zzW2TO+OPfEx9l-)$LGfQ@Bih04FLF^|Hc0m)jKAZ#_25;aP=gpC>o@CwX0$<%8g$N z18Ng}GBxqWzh1!pri;+**VxHW(Ye4ENM0oDgtVarfq+7{2EOPGfaC1qEm08M9O^&Xh}KM&-qdf2VnAZH=K59gsA&LtNmfVf5!1Qj;9Hp9q%#u zhXCu>3%cuxNqM5c8SY)6Y*$PQvvvVY08on#Sy2tE*9G;7pnp^mZ%RuH8zUnj~V z50K-iSXu4d6;b~AGbU}Fq3W=%q{96g6xWo@Cw37eI-PF<^ngoYe#Uy=^UAtL6!vq; zv16jp;RdIUo_1?(-dD(2&|gSoptf#}F0V>%@3e8q=PNi(Y-O^< zyTXm+mOER6i%v(?E-PWSiyzp!b-W*ZUZJgF6otD3{24^yn2TeS%C5WGpV^!wbW;>5 zGFwbR1htENu9^rpSg^r8GZRO{&6*fnn;Q$*dR=fwogJfAAPXE8U1__Xs^@D-tj?Dz zbHI9%Xc`j8lHbC6QB=_zl>&=AzV2yyZPsCIdJzi+ZnNe)c^-@BmHYX98WbAeIJznX zc_ILAP*%I91tBSqv;e zAYE1c1uaOJz@m0Y5daK4Z%K82r>Hn+bL%h|v_LzRi~X&j3DTLGd(lo}4btY0A32}g zqLZ68OhTr!nSL~FxfcCCwa=!Fai|UHu$caJE|`iIbkd5BA-RL14?H@6g`EafK27fV z%oooQ(!R^aiO8YO5m~HjD;PfA;S_z(_=)o+-srx*m|ynXtdPYbZ3Utb6EmRQ+v@oq z>aS``+*`pz_v->Jx_cptC0YV&=Z@9^cDXhI)H~_9Lzypiu){hKep$eRmZ| zA{wPS7J_XbtzI=}oX(N4HY8iKFKwNB+Jdno&+|=No!^B;50~frYY3rcq3G-UGjP+k zYjk?w>moKfaguPD_e{v_LZW+ViPSdnrjPJRD50&$l}H!zl95-sCkF?aQoH7M9f=%$ zJ2zYF$Q5Cl_ukv__8p&<#QdAS>6;p7`}hC;-;eM7&hPxB-RsqAg%D0pPw{nM_jUNTZ~Hd9_r34Mhd%Tne9O0d3x4Kjeg**W*Z$gH zL)Ue0*<;*}&#mEa22}4`brxP)$D;&C6rNRDm493#720JgvuAb}P_=?wl*8M;V<_#V zalFgUu^*YN8dS}aL{o9KU?O+Y1d0H5I>P}C-knx57s)I5(zF+JRRwje{`&*aJ@$C@ z=O1A8ipTZ|&_Aj0Y6CWHT0#D^E97p~vuM-~v)uV+a0m^SQ^ghNGtnGp`Wanm-CM;!$& zsLfX`fZDSh9|Y{)>2dj`3I5undm?z@e|`kH+Mx~uaJEI=tT4Reyd_fcdL)N$6I;+R zocqS5zxQ(!yH5Zi1o}Byf~-pCKAC> zXHG4E*)P2m#H#^e@0!1K_1byN75UDJ)D`2BJHpmW)b(5}5uW|5*^Lrl%5Wp+o+-my zchuGqyVF`!(ZIBwTdl}3ps2N&o7g4ihXrZfv4iKCTvrFg8$BP>HE=>za82SHuej-D z(68GNE_L91w?Y5|{yZZ9ERZ)yy9lba>n(9}LRSo-yMV#oyUWxPU^kVf4HBw)Cu@>B zTzJ*sDB3+Ibq3Jnd8K<#<{HnvAZ;A{=z$yawa#$aqXdT>9sEIP@7Dw^UAreuA3%!` zPW3?kMo?2?laqKEm0H42P+)!IUL?mA&EkT`{x~20qCB9&$QBuoyC`V zt~RcGF726wn+e0671A0MP*V+!u;)GM9uKW(+&I?@RKSvoPz%^mUltv0Pg{tEiteq& zil2>Erte~qJf3NhtQz_bxeXK09ka3u8HbV_V~ zwFGyurDbYBLupo;rDvSrC$!>I?c>RNUL5T=Z4FIZht3h6?zCuC{A^!)GAi0T z(M^iXIS;L{j9lRl6L7z4v>eGSRMy_Jm}UE42I5VcT?cN*+jdA@nq+^b4*E$dOwSri z!L`riF@B|C-|+|k;2*@_{kwnnlYaJ_zUiCrJ>T;^&-|Hl4&U`%--SQ(Xa3CR#4&y~ z_x@}Ga#-hB{+&k@_(3Zp>v;$mgOW@PmHPu%)Rm1}oYlpiG7Sc+T zYl)VWFO^G+2J|h+n`j9%TzI4naCkuwuYm0%c@taVqC|&j>rf(-$0f&7l%F}ALREjr* zwE9D$nzMF{@`j!AtIrQe8z7wl=O3-uyqd87*frelfO@k>edhz@ZI84Kv%2i{)XsVL zt`6fl{pRDopnp8!L>LKxi3Q4#;jZ`X-_mpEydPtNyBQ!;LfNbsn9B^;eS@Hq{@e8Y z7Q@|$$6pd4g@NJr<&6Hxg!s~xCZy!T=XJ#Kg&wBRPn#^EkMA}4g*Io>2H3t_&|em8 zK6<4EgNl4-jj|@69N_cl9}ROr?**mzxc>Z}u-y9$9Q^^p zAJX=6^>AcDP%H9Tr(H>h?#W0_xLzY+=KNXi7X_0-p{{Z3aP>YxURTHjY+e>@UMpC? zIx0U`Fg%DD&m0cVxh7({eI-+K;%aDxikr`0V?1*h?vsk*M%_E7%3|=%LUt8~POm&ZBL)*>X_65)V3VP6P%HpE7A zLvW|46fH7O7anQlaCqQIQM##EJxcH+brh@!)|BOQ#qgk4YSEmW8@IZ!t2V#lzn~ zM8m~LNDYez^19u`y~PjQd!{=p>bz_mj&~?j8}?|v-2l{bb;f2l*tiy?N^p4erE3iL z1j9X@4@bfJHS2m)v&Buo>PbP|@x7l{w!jvNc~m!=R1ws=t_0J<;Jd|7M6s9pZGPaIXWUpwz_V{ zg7wQsNUr#y|K-2N?fA@%&$ayJ*UZQKbA5dGcYim2_wWAQ_#1!YZ{SCN^hfdN(IdR@ z!VCDVzxB7`PyMMsg|GRVulbxg#_jmr7!880sB7B$I8{XjgSJGxSyevy$?rSzUuof_ zL1n2d)VCl+KP$@7s$fE{5KZeuRj)6-G6#xrpBikn@$i;`zIKH~;jPsZHY}BJVH12? zR>BRwTq0k_;lQplEy9FJ!B|hAjsBP+$-$3;-1)h}?$DshQUqz`(G9tEILv~lL_u~A zl4;YG)mkh^p|^O%0zQbw!F8F>CLYMQ4|~3ZEf6i8!+7qQ*mt7$7U(LwgKkI&G6zu> zAgmu1vEVN=c=1}~D6I(N$BM8o2$uuODm4Bl1J6qC@suGc zqxKzY9~y09R#5kgIk>3d)@T3S9TK8<@Iz4EAJAPT3Ky0_{{ZoRUj-lj29lF zKJNC+x|^zyNJ0OEaDFL;0$jaASqBEe0_Et>b4n^&;+rGU8Sw^M?BO%33W@Yb@;9fw zLt3!_ZR#gwCmDN z9xdz^ds4M)t}PL&zM$z1ERr1C!z7gkt)^%pbr_)V^`=>&0%l9`w`QZ|77*+pXawV@ zYy2%ClNp9BfFB4Wmg?rNxEFf2I}kE!Tz9Wp9Sdka#LcK^g|fCT^kR<8T+%xKyC(1^ zA_={him+}ScD8J%EHJ1eaEV@oq#6a-uKN#N8@Tvsr-6sE#Fyp*_n|5e}l< zTNYr#zAO+(wVi8qXv*?NV?oxXjEiu;1it0PtqSE_SR+i}`G)c2J&wMnseQaELixdqPx;2fM)@ac4@V(6SGQm74!PFXC+#st+gTb0O+2k^JFnK ziWi8A?@~9$Zi3AnMT{(j679Q|s`xoN3WRFW(u(x}6fwqvL8ui@M2mg59rL&Q_^ffv z-wMb0On=7*KJWp2-~%7{kNVEH$}w)oTYr@3Ddtuy#Z^>gl^(OYdFMj@W|#v-$+g9c zrE^-TX(HV?F4LIu5*W7gTHXds6%O1WjQL`UHN#q z7o@}vP`z=Glv;2H0A(`=r{nqD@vj=>)?kGTa>H{_4&B828TSRC9u= zIP71Th5Ew2LXJ=|IP%imaRMAWWs)l5O+x?rapqMvZfhm)uUF9;RXm5%rPCR`=iQ~+ ztBq8>_xl9d9U*>A%Oapbd}VheUp*JpRYX4P5uO}?DKUw5j*x9wkiD3kZ?bp#-3XZq zy6cWG&Z~^@WPrOl%pY=So#uF{B89;ruU72*6tm>1=wC|Og>_iHdVt%j$FwS>PiLW_ zKEgo7{3RE7It!T8rp}KQovKNjO0gfgq;8Nh=_2MS1MIrK#eM-hq;(xoOxRoTFhuF|0hYd%zXAy*RB0(rHcuqG8xrkjUgLy$M=pnoEWHx=vG6XT6T z!lZP7)*W9IQfA>a;$6ItX&tMbh3CdF(3*3<5jtNjj>KbW%M(7ng*Myl-+^2OPfD;Ac zxHsimL0Ne;?4NzsV2-VWFvIgoPfu`q2&)qGq;NBkn_gElq|7C#&DGp(0a%4Dk=A2} z7b~V0M{F*R*galjdMRT4I=NvkRjRfE4Tg(eyUp6+@k1dTcQbdz;O1^o+6G8J!_~?0 zb3E3H(DlY&(-C&;X4C-4NacAuA95;Hw-N-*39YOv0osC}Hme6_L;Z6;RK z83tTQIY5Kl38Xl{sY<_fSQFq%ojrTKdA%yMKC9hX^y~yZ-RZ6sNJ-}fRAk8!-md)h zW+h}}2@_l%O8;F-p#Wa4h}VhT&)|vfaO~`vLU`!|rgKsVj(45X7-pz>*d>J-d!jkK zpmdRZ{1v-a1~oJo|19ihP)>o%+S!dNURa5S2mqw0fRifD8x+$i_ca`9>+n+7fS+56 zfEj{iyh9-}rvhV=>q+%{*|{^jBdJxr;TJTBg?G6jTFj0R@Q@TBL4DH|^4;Lw(KjAv z@rLC^6En=6K(@X?DN7{0b!m0z5)iM+`7~wlx);<-?NB*jS_`H#`gHe?D*S{7Zzr_W zHMMo47PKj(@MoLbNOFoex9((BT0qi!HD&F>R?a8wrZ(Qc?p0C%B%BUyj+y;fUU^=( z!dTfk7f7t|kycG+*VRP)Dj?0-!khxQwoyQ5gyr)#;V=U?WbM+4a9>CZ*tUJvs0XS_ zy|h}&-8_$~%n;zXGxW!Nt;4y4({5&7(SFcP71cU&r9zydVQ{+6?bv>-Sie3~hr)iQ z9N4@v4{w*yP)e;cxEOB8ClG%?RHH-y&~nU83pz@fuirYO0-+6~j<~DnA9D_dT}2oa z2_;0F&F5L4nt%Eo_HfGFEw#_Lc?giw;CM2nBd^*#;#aThb5Q3HLu^4Rl2Xk4Ag6qB z0WcJbua(91Ro#!ud@pU@+IhRN%%X#KJ*r|}pzk~=EhF;YdUa?Z>V@dB$B)k70OU0f zKAsDXFRb{iCVsb5R}rts9;vly+~gHI#c;DHy+33{Q0Vn6uFEC528ai8CBiG9ARIhO zXAtuWR|H)l!pw9&YG8bldwQhj_|)^#IpXrn%Lg!{{(@Q)PU=3Pzhmn~Y<|=QWzWP7 zb$*k+G0&l*=qE!}INfs@+Ysdl%qW>RsQ4G6y!tCg>$r&?@#0SRklXS08@Gx1?YJFp z(NUuV4wx;Wyo29QRG!`sOv;@jf4Fl<>!3nP1^zHC;OGlQQ48>T6(ZZCaq_0K(BO=I zD4GpoSOK#G@`nT|5eR_!o~_Qp>$yya3934)|^F z`w0HayFZKn`SMHf!<#R`^pQ2aUdM{zj%zPXQ-3yLB^e9CE>ke<%x)(M6!#ZW&pWj{fQj|nZtQUfE<#a}VUMi4Q z4pNIIRi$}X`;oK=Hx`7wp!0;nO9lf^D?X{684BpnJqgP5y>dAn?V_fl>g0OE)V_># z6iW(NgfXkU(z&@1ph8jx$1Kiqeu}QQTpLu}B^7H_S_GyFtmfpzZ1i$ZC1tnPH5!>< zTk$RIRg6oiD@#EoH)ML5Uj#h)qKNSh6|pz3;KZS!it1bB(p1)GehufHaqp{l5SQoV z$f-3Sv`8{$KGRenBj+lE<~pwvOX9Q$SBk)SgSkSJ8zF3dD#+V_v>{Ew5~HMhVigs) z94fk2h!7@cmbfaUmx7ooW|<09QwnCuR61D*ObNs*b*R*)T3;85?h;bor~+CnF)sgd zFLzT#yrLFEvtiT3c(^;CZ&T?$2F+TSRA{k#-16G|RIz<&7G=yz{VE;Q!cO_p$BMXjZJ$CF z_$2UJcwI~5mQ2Zg1x@Jx$3Eu`)X!Y<7sm1gH?MaooBHk>%- z=N*QE7zGo!$GQYas_<8wPi|7kd=R8{pnavzWvQpn%O$kEs?kYQP&D;|v&V$QyCFA$ zT%XJQK6C(3n>K*h-deT5o94ZYLT+ANW@;-2Sb??*;G7`q`Q?7zU)yue6>d)vUBchB zm=)eQ2XDvQYuqO0x8ruaMTg%}O}oZfoQc6p0dhu-0c8_WR=#mbT`o<)%LzGc(>9=V z`ty;TY$@zo4EG}X#}mTi14`I7o-2K2Gn^_RS1%aP9DG-?y&CyKjI6|4_m5t-k-p-d zNx21))7i4}44|U%S1I-ajQ0zE+xtF@uf6|o@fH0iu#yS!OEUhce?PYW!xrZs%X6oC zth0bi5V)IyaCJm{Eg>AvaCoquiwv4Dx+Cs>wLsr#rk1wpJ$R*v3}(U zcTDidP3z^w^===T6J1`ROx2#ZQxYs z2w*_t96N-?2!0jjFS`^2VyC^%Vtt*52rylAO*AU*sjkiErrq;n08&QXAK~p6R=T^U zc-zV$-tgas`$2inb`L71^MKWBN4T3K%BrIknOfbrsbc#|YK{Tbb6$FzL!#F$?8JsA z1H!em``tfs81Hr(a66Rb8%NgeMUB*VSiL$hVOz5(!ot|{W}y|wL=yxzBnFY4*ZVSe z9Md|&4-{kEKW74e6|2X9^d94#*t(Wx%T%1OFeXe4twR&`1#X~ccG7NFcU71?de`jf zx*G<=)7l|cuJ3dq2uF{w&lEL0b6m4`3(9%M&2>a~DcC%uQ-g6rX|1G1A3?Ld@~WCl zes-RVLN=CNx5*OoO!SBPzl-j3b{szxl;BZ>T)<)$WfDkaYj*q z4aUZsp3Y-acXy_!?r48z=z3X5R&E-)Uv8;Rh;9`FaJXe{0Dt4IH+Ye{ff5lxb|z6mwDJ?FlZiko+J$i1My z^elL)RiBCN*`VJ#PcR&^Dra-@l6%a;$8t}tjv}OP$g>8;LJ-xKX6a`1)w1h~RH=Qb z`&)Oz=V79QZFy%ycJY3>3~XOca8qggey9#f2`o^!iRW4(*GAZv)~)qp(R-yyq3t)0 z8;NzTb0iwePjhl;_oKiyyHtRMWu7b1Va*=YQR!b^=6aa6g0L4=^WXEHyA9I)4#NfK zt4lzCS+RL(psnLVH=$`pR1c^7oxP7J@aZ5yyV#c*t4rW;&+|Qf-y!TP;*QrfZ5=MZ zP!TwZR;p&(X9c2emzzp_yrJtzyh#|(ItsXoCfQ@gc(+4Z(?P-%)~h(`0_+yTo+eb9 zN)t*1_}rVzg7Msgx+<8Cg9#)iD#4ddFsW>C zpb(qJ0xFPXc1v~BH$P76ib$y_-T}SlR*s!9=*x`9WH4o-Z+Y#sW1xaZRTJ#!C_Yu@ ziZDCWnn0KeG{6_vLb)|wXGrD?(qOD5fNvbPwfz{}`zrp)&wdrUYX?8fL6f(aXJvApw>?}JP=jFgq+;B%3*KJJ+EGIVx~sWp z(Cr9M@2@lbu{H(PSu}>0LgAQ^dwMB%S6QKR1&7buVz_gT!*hJ0vg63E!`VxveUG0^ z)X6$-f;ypz^E3#y1~lTH@q%_jRdRi1);(l``BcKZctq_vwTix|fp>v~02~K60Of4M z0Ls+ZbD;p7L5uY`&k~MZ!rPyQx;KCCMdw(M5q1fy*O~McPg^?+-~hl4sZj&s4S&zN zDAjUl4Y&ZD7C3}K7$(tV%fn5yDgsQXthU4rb?&rOF!?Ld(SsUHuEIVy>n}?h?3Qp1 zCDhC!T2VD#StbYz1!#b_eU@l6E1p8QCB>7RK4aPiwPbZkaY!@d6DJ)vhtrDdqkrUp$F3lBs1 zL-SmYcV=5hsSA;`JpZx1y+j9hgo^9obQpC>F9r6zL{K9WURe}FBo~wzDY~iWYhL!# z8ko+aigi|GbqJ8eq{ijK_l#Oh4R;*!8m(vy0pfK6YEgs`-Z0G7z>U5^maEhGb%I1# z{IauoxcE1{#+I0;0^T&Jq{mtz&^N3t9ot zI{o}GAdbi)L_rddxJxkS4tVv}){d?pE8TP%M8vdptr%Vc=bvOWvkfM? zEU2f|EC^VgpsqVW1Zfjb=BVU~?kdCYN4R4`vBIuMi#eKjUs9n~Hx~l{AZTGi3NV~| zWB_RexQXJgJXgKHN5ap;VJ@JX^9$(%ypJV1IDOaK`}x7junsr@++T#n;yD z@gpJMh=h)t+ACn)90pF}1o3Ku)QIDKjaZE5UA2&|wkD#T3&}ut%{S=P&)>oSg}2IH$o zMZM2~&1)I)CL=yN&i5EVT?M4`j{d^lQL#5NxY@ikz>OJs9dY&f0assKnCM&!R*$I0 z>yH)P_1K<6=@u_{<-^(_gfq__B9S*F+9!!iS=`f#S;hFNXX1cnj(F3RT)S41Q9+TjL(ypBxja)rA& zLRPc#Is@I(IQ&jD0nC_H?A!N4xsgoBBvrW4K`M(`{y6g?o0@Jegv~c7vPar_m|t$V z8QcArtP@aC41lSN1I}e2@P4={<7q^Mu2~s`$zut|sTUrVTEvnge_sx*up#;U`njSLpiF+)7Q(-2xJ8O6Y0j;hms*(stUf zOm)_ufF@)zuZgN~@T{u;e$a$wEGQwcYpsY8Npo^eG>~%l7x&sFpoF?mTb_#p3(8O@aJ@sgkydnU zg(L0MTT;H%7NPAVA?Gd?E$s1KVoLs{w`7e4k=zTW^S~rL)ka;iPNU?4>7qljF5)?m z*R-u8uiU{O9iiLy{GLkA%{q{j5z@U%+fVAPrOz)l$MyAg(m4&Oqf?Y&V2}&{5erX6Hby=7Ln*QBE@S$PaPFY zkR_{q=@mQHWgU>UC~w8(v=SVicbLwA%}adN4H=?&pg&Y}yNcaATyt4qQVXQ>9`N)~ zH!C-Cq$|27Biv!4yT^Io-UrU^t>}A6crPJ4`WqssW=T5Hv%M;`z3MgOo?0Ve=USnw*{0UTd>2;2Bo)+kXa$vJGs2|`XApF? z0X?z!vzSe3IeBe`5F#S{0)1mtL#aTxnOO9>9dGM#o0#8@+woQ%UV|U?B~IJE1x3?E z)P$_IO+NSL7sSBVjT!yTc-q<1mu6W7K!EOY*7ea&LlvrE45+3kJ;2s{}czkelyx^~!TL zUu*~3LoGVY6@YbfWlX4^-8+9XV!FG+ctNyRLYAnUgszLIn)DkcB5oH}P-su=b zj|JW39{!jRZ%E0IT+uxqQ1A7?I-t4=Hvs+Pk!$4smeBB0;EwY-O3n~p;6{PpPbi(o zc&}pz{Fnhz0U4eiA)qE0YR+-`>TrXGGp_~ z1hYtL`-~Iv#-9?bblgE1IT34%oW!Lu4>E4=Fh?~H@ZY*$Ssbqn^762PUN0W~N zw1Q&m;Ayv$dpD6B!(BmDn<{^#O@lvU;DmKc%Oq(vMb2>fVva4dNEV{K6Fcs0MnBo&zDpxH^r>j{4JaFfUG z#enII!kdORSif4)T~}<=T=+BrRMUZ|UND|}LaT-UE`Xwx?EdlmO79wMU2<*(vFXfX z>>Y-4K{!^#eZ~5f%(XWNVbTrS?@4P~XbM;Xgcr(lpEiQ=g8vo|4sw}z|GL>HJnoZr zwgblVsKp&YI8@{nuz$f*4`NNrJ6e@8`L_FNka(vFdDvIv9=Lf&K>fVXs1*I;q5Dkhz%VCc*0A*a|wdb#w3sQjz>fi`eC;UNGK?ZBL%g7*~wvGE-gv zbT>8ObGooE~dd9tx9Zaq{TZ-ca=Y99?EtM>n;?HIW!R{0T?bsdFg_%177?1UHo_P zzre$rEsh^O$Lf(o-03j_P#~x>L*>;fm)z1$FlnL=Fd;V~nd%ACJKpzLyT}veD$wWJgw;@iumk+-5&a{f7c2OJH%Kg>&GNw-Pd;mq2zF^TA+gT! z5^mRgjV(zA*qI$N;?6n`q&iT6UEz9KxpyPg_w%-6Fe_k}V;E5v#fX#nr{5=~=%GG& z;>~j^3T0m0LxcD&VAwUPc0uo3r^^Jj46Z4;0x@tUu(rXko<|y#@hP94obsdV{rBiX=7>xUwkbs1TbWP>{MJR*9pW~2)I zd>?i4D_=9sGzYhU;E2sLo>N1Uh<2YdT36Ma3ev_kcx&4D#s0yrb$?V5z)rc#=HILx zU+zQ7n>FaTb(t4*1?&2W2%JWhHsBBMqYK~RA0 z$9)qXwP)idCirlI;cj3Nw*$gK(3gtpJ*tU`>F1@0b~)`mA-aFyr0Z&(Xrns7yIBO$ zk^d|c;53=FLT>ZA_VYXev`C|f6!XTm`A(#dt|dD+SzKoVx~mGw)SPI@j$Dz}TJVA* zNlX`}oFc8N6C!iWdBwidp`ow%Y?d#r#dFGwcR(w;sWV5X5dScrw^!wPL-0Tg7E&pw zR{cCDt%KiU0d?xA4vJD+Oc|k?{EV82Cwc-#_i%a-0InlHvbf(ULv`Mxp=gJ8**bqq zP=tYApXmnV=pf#q^y&i9Xn^``>lG?GH;c7|p`a?nkB~x9t}q&By#~Q>!9dsP zzcpJVnS+)pglh6x$|eRu5~dsL%X#3%)H; zou63~y%MxUpIxA*CPD!qyq9KsXSxG^$W26wusXn0zYV79CU$Jd5$u_0P6cupn3$K` zx;XG&3le&|i-ejSWj&`iOVINST|OC4bI!dAj`gZSuA+lxtHa>0pmd4`xEX-^D!`@* zk{b*fT8S3X-tbcihlA;!Veka1<^KsV4~~PN{PIQ zIXSVpJ)w@emtylv9E;&fekmJbT^CpJrP6Xo!>z<1!(Bc3m6+5f` znBYc1^&RpGRM)QT%KEV&ub8a!#6XcZJ9kZn{E#U~7#4e*@|FR{)hx=)d~Hh(9MpoT zS`ssND@$Z@YMpm0?Bybe2ki>3=j(NoSKG|o#Pp`Kxv0kuy;3j+KD#FBw&1?YqCjNH zU85%%z?msaN_Jx#(7eU_qpKM}aqcPrC{Pht#v6Wfq35s8fJ& z#H_k*z&I^nl9!B@(3gN#DBwJy5NSB57J|2v1rZTSf5=hMWyy+EQ0v4-qf z0j)u>yuZ1#B6*$BKAwetmlo^iz<6V(?^UYP>mF???hXB9gp#Qb*Lj<@KjQLF5toBW#H2}yPC!YM}yV6t8{cz4HXR+U|a=ILt5 zv#3o@Ub9URuP20^v`*9E`H11dVZ2M|YTS`a>QcpU*Ebkn+!am!H0T+D5+f7js+MHc zVwkFsSiy7-yzpB;f!B8%TwbmbKi(ni1l<+jpH$_mD&KXj>g`~Vm^@!}@nE87z}0&l z_U|l+Hw^4#0@hC|`pb&#%LArO!0~~{c%jx;6*%7Yi0?Q@_sdUc!zAR9!n~hF7<_oO z$T@dJ4GgIv0;B-zM-{6l7#hs20- z|D2aTWd`55pl(*=BW7A!8GO6V(*;ynkWu00guaxPKw0;Zzr<@9@33QAMbKTQrao*a zkbKcWM$!$!o~pZtck~ML%~-uo4)%EAHKEs}&xE_WKx?ouL6pCZk(^}N^eF4t)<7#N zSa&Cp3Q#-cycfckbMKHh9@Y1azTx*1BxfR1Ty0$^0Q7Lzk+=M=@Z?AiCeV^sctKJZ z1UE8~a!)eSc|=;PBD>o5Rvp}`b+bPYyZI!Etuv$_%$o;zkfk13;ikD>y2 zGoRaYuhYUwKI?RUo0<@z7Zd@;yB++fYUrJc-34Gg6G)*j z6u`t}_YOi-S5FG!bw<3J8lq#o(D_nzO`Fi11=kL6I29jb(9Q2`o$LS%7rxPLxL+_K zs!&jX)8d{&@u%&)?v4*4!ro*3a%$@>>G}9Ui;&*BeN-ejiz%W6c%Pa`pCVl>@pAg^ zv3-rtT)DAV*O2uZI9oB{$pzgFt3ph6`T1!rkm3R9I4>870vk??r>J}$ZqfwMTqH!0 zeMK-)w&lI@y~h6fSTJ#)O^XR8;uso?NJhvAOH&F2ZySw*^=;C2;Z z51joHf93GNVY~yl5qSP5Qq!U+#>-b8eG%%dR9(lGp!rLRzWLpx`)|PTphwz}FCO>Y z3#(JQRYx}uHxijLZTOu0L;*1=Oq@LccPMJVH7lK)b47_-3<0#rJ}bQQS&O`)>- z%8wy5T0mMB$)M2qLQM_+9t#_J<(lXqas?(9A6QIMbU;EAy!2zmcuuRt@ti*kdtm!Y zhMQRIb*Ly1#2t&)bWM;}6se9*4B^P6-r^sryyxEb2YntKdo3p{`K24C{vHT=ZY```voRrE;%f?^fxImk4)V^h7g+_MMjc|tuzxE-*5tzz}4 zpu3(uSo6wZJku9sq`=kT`3`P4SAY0?0-+_$E->M&Gwj|(+-k7Eljkzr@o-bc>T#YS ziAzsX>jn?Gbq|;bx)x-~SgBquRk&^TX$m#&yIwg(we8t z9pRJ-!v>g~i!^v4oMU31k|x)_aoeBnmWzpVEerkjKhB|SI+V`Sc1Z=J8a#3=fbvTH zF)0^bIp^BBuU@&`M{=;It*H-T?$*LLQ7=D~lk;fGxm`fsI)v9%5UwL{ymibSC{U&y z7%_-uDtiBz43kDu=8msdF}+eCgTlqrLhoS#KTcb6dmG}#uGKNAbyEcK zgHQpe23@t}EzDUuVXo{C$jdZLLf6FS$G0=?A*;= zM@ydRAx-!+y_30*6y=zA*A?A$L4Qfg#d5D_Lg$oQACNRLYl(ISP^Cec{jnh2jM|~} zkgU`wolgSm^l38OxZ$<&dR;1T$E5qb14@D0kKBXej4a^u;k`;*!lQ@tKr6Sxt zX-$mOO@i)53$ZJKGd(|Bi#iWZL@_HGGNYI-M5;LZM8WEjpuu}8dHSaL@%oo}3}1Z2 z`NaYG7=gzt_#<^1Zr(%dxw6jq!e9Rq9`D!KzjTkB;zMcAEw60fKUIsTcwP zS@KNO4%9M^LVUT`_hClk;G0#ZohQnSOkn|rd*|`K2gI(EzmwKHt{*CJE^V*K9gE^= zEs)GP>PIf%NvSW5L$96m*)k1n{+mXCoA`6y4x8ruaMMvuz`Z?jA1H(6N-qkx5FGGWP5-}+)crfT*s-D&^$E1QluED=@Cm8Pm z(~A>+(|dmjA9?%$*N-2tt26=AIrN1s$_cLs2j99GmM|ADs8UVj6io?sqU}j~Z4KPL z!B^k?CH$N23jxq;w<$XpOTbHmj8$)e3X>0mv%3kvB=ARa)HknXbeD-<%2S4nUe$pq z+JlZS{NWskcRPg6!|$il`xzDquPNvn4^R{Dv?Bl0Wnj1~@JC?%I$yG`qWQ=3+Da4a z6IDC6t}^|$nUvP(8n@34>g5~f08l3Fe0g%7t*9b}d{-IR6(r1$9A4ukF4go~w_G$a zvd*S+sG<U@NlI1WLQOE;kd)WWL>S&C zum)RWCdz+N0pJ{9@MBQURu}?UgfIcF&SN@{@H?s(Hw}cmNaP)ws8kUus@rE9+KNKZYLp5M!cP>bt;4QRPEo2#qm4Ms z5dGj#F+-}2(`{bhH8_;sVYrxitNmrh8V*tf>(?{Fp51#pwi`-AB`lT2%|giKO3kvDMDk6gbEpartog8;;6BJ?R=)(I#j*u_U25A?2@9q*WQqL$ykdc{dcf~> zE>D0c6uG}DSiL@>d*udY9Z|Xfujr^M6uY9W8ezdjxwYgE&xxCLAkAviX;RiSBkb1O zzFR@7Or>)euh<`^Q@wP0edV$w6o}sN;e4*Fr2d=U4To4YXk3)1pin>otMupJ(9!V+69k012 zy#`@2e^P*%sy-7^c{oqCU~ltNw5T;0zsekj<@BwP0Vk{ z?Rbk0`hxmatws|WBD6XjGgU=X0UT|n_`)rXQ%SCvo4Lu0K+CDhw@Xo9$W8+fJ%J(^ zbHFe~gdKU?$~BFW?7?!}?=^UG68!=dFZ^rk)UT0IhrAM?9Sad!13YwRdbaY;3!+oiw)HG;C}% zw$r3Z8XG&dZSL6Cj%}Wt?>p~%UC&Q==9+8GImSI;=dSq3PBC|Ah<8u>2%b}El0S}8 z%0go5i2FKF+ddJq&b&3OeN@Foq^l(kjPxQ~E1qOPRj``Z{p;MsV9V)A)w9 zC&raoVh?E87)#`fQm>%5g+c-S{EtLxxVt5YE}`r6159bje0c4P^$%n_?%PSM%%Lbwm(JJz;DyHQL$_9AArPQjzQ>$Mj5SM?A zmJ9Wp;N(W)7WYFp4O@(;Ne$yWW!=RN*R@3I#ljrE#qvHNZjwg7 z2MswPdv9fZpfoo9AopscMp*k%Jh#bt{oj_^11A_*RoD_#gH&4oN6V4Zxj%NwkDgj8 z9HP~+f2p`o(#oa|j}?*Bea+Zr<7SK>9fzEi2qHOJ9E%{ohPfY^TaHBSA@WYb2;9h3 z5yyzx6CQuzP^qOpsKxsia86I59~a*-LyWi;Bevu3HDMzt1pmLV#6NRUgSob^cE-)P zY#S{>XVO)qebBs7+U7Fz2vaSIkhJXlM|FmSrrZ3viG7I-GM5gS&#P4dGr3l_drXPN zI}C0YUmg<%?6`q$bFTu=D%8LD zT>FNxcsl!(|$bP>96r_0#=v$UxA0-X8Jschjq@f zKQ52iOngO3CmDOnbc}ykKnmzHhUUM-p(kGB&Dy#7mzmWn(%?7B7qNta8k;R8(Y#Lz(7p<6rC&>8aoh958qWhn;x zo^_^TuNA!`vuZnF??k@i+FK^ATy!3N=z;rMzqvLNdi7lhawbDKzW8vW79ox&1!7_} z?LU}03j2jzJnzw5M}x_odwHI%)*-uFa8Poc{1E6ge zKdkDg2*j}7{kEm*O!e}9isS6WU7y{QD!;i;~ z|NlgZbXrZgr;xCNmG~{Lrk6r2_8vMyZ{+MAd01QOo&>D4MOY%#BGh5hVJM+wd0M*c zh{|<2y*(l0sKCZROR_y(n%v)AnrkT5Hk(Why(ob+i#E5I=1TL$m?`^IoE`?Y29h4a z?qRQWM)5K3I#a>kS&DOXrt09>TFo}Oiv(PB)w*;H{^aY88%yJWm>-e2uka+n$pI308Vragb}U$W`6`$==g(m6B3Q*$^851(pyg2+r?IkQ=w7LyTgxV%Puuv#my@~15Bm$O zwxKAyr*!PL(|423;v2SX3=+mnhU6h_-vgZ=bbBT|Tmu zmuAEZ#S5DJN+JC$rHc29+&Y+N&9+%bRxF4}8Zx3a7u7bU&vjHp1tTO&?niCoYqq3O zyQ^2@jsul1jRwz+B>$P)vk7VEBa)fh0pas^sP3o|xQL&8Gcc276R5LgcNef5l7x;A zlmK-*EYJ&*c|6OeJWTwzkDkMPFU=S?n> zio(6HtObq)U2Wk4=o>fA}h^SLYe{+e2XGeJzmU49|kv0JCR zpGhf%O@R(M-HK~kgv30^4=`^hdyNAIRtu_EPX5sdP6GQ?;u_auX`hIdP(;f?8}5_8 zU*N%aFA*&1@nuRzA>=(G$NLOm!R2|7S^26Lj!tY~ zPV06gkoz}e&BB`P&H;tTC}0H!vYBJ=bzhxf%o0CAjt8stjhz5BWw2%pi+O)Bd9Q zST|d@lj#8=EjaP#r+f@cDG7rb-EP*ubBM69P$gp$E-^@If`fW-zM^*ny8^I>2jte*=GhG{Z1IN zFb1qpCd^(#-&N(%^Ifz@V%kB#S(S!5hEbjHG-TYKtb2gxKgW#T9cwW9hLDl z4aO@&RRY~@;Gb1y(OWNd7v}3Om}jE~sT&HU1<(Dh!N}&Zvs6!P^OzvB5b464xyY-v zrUr3qG|;k=rLr#=-iC!(CIKhDa-mTw6M>ofxj&uCgcoyAo87E@At7U zqih+QLgXAT-%seUqw#F&-7$<7RN7Zsnwu@RcEKTA)BkUKD?l+yvnuTQVR#ANz=-#D zgV^bugwPly>_22ppaalObBCzUMYhM%5)A~U!K}=~3rp=Sj_~H2G8z%jL%fN{xi~Zn zdC1@d6D&$tMRt0;sZSfRjVN|(T?SgRN>wIPRWpl99;ON$G}s^nJ=Mvo1W>a%67??F zm~Z`^+*KpmK}_*ci>(xEYdEL3ir;2k)A)H`K}xhdi3Ar`8v$r+*Gdn+QXB%Xi_PoO zjqYh&Dp(IZtMnWr7@aRHhij?rM&}#n=CSN?BF#I$P4Kw8-Mun>xBu&rVD6d1_4zjO zpF?`4X>b(-Vw;d-z8rtrCUj0b73}0~jAcuBv&k7{AqFA8(opY@W$!~GQ{*g|$bDG8 zGgptV0d*b~V3xg8iy1URrdu%!ofS^YZ_^~;OxTqJ+EFD;Nh_UVErU z01#dvPsChNIQd=Xpnbw9GJPIT8j#_&U!-7hEZon!EeilxR?0 z#SZf)cS?V6UIp+)w9iniU3yn`(L&)Opk=iUcC~n-y|cWyZ^QZBkEyWx`9ADNzPILh z|JibqY@O}9z#PBp%@S?#QzS}+6Aa}?<&ETv;JKa7^>&4mkMOq7ipp&iZc#sSP~|`v z|2u%PAD!;>`C7X7}fD$puTk+ED@A-H9+fB(fpSa}-JL1Pzz0kNeZ4ON-gZOC(u zZ+K-QyD?22j>$=fhrU8KLt8}a~k@P2Mj^aN5jQ>;cIv2dBH_=-qx%$p`;wmAPR5~`(X8s#CbUZ zD$j+#)xqg1z6~>T<2lN7f%6(#2r81H;^e1`=J$WA8w+W?A@NUxw_2XD0B#cTndDE_ z%e5$K1pINDhT>Y|)|=GEy2C#Oh-w;z^bRKOZuGQ0WR-`%4Fc`+Bz*yE5~7qTvAlX>=BjU6TU-{))6vEAjzRcz$Q-z0=*=uZP*`k>wAk(RC? z#jFt&=qix(^GmzFS%s$D+iTlyHKQDrzXkpETBOTKk`r~Yi?lQi~G|*t@qJift$38KNglr6`SHw~kJ(@Q( z$F{h0K`F9K54z{q;NNO@u%yw)oC_dgVQb?S#+A`Vb~wYQTyFW{Yo1lX%^NEsTS5m_ zhDw8Yhsb2FlI`|L+Zo2?Zer`_$#X#PO=PQ2Xo-VoqqoE)$$dq`{nVg z5jRe~ythuXwr{c9c(maZBE!2_8k51ei!?Y^(f*`QJvpNU>OO*6AMO3K%ku_Pvef1 zvK9*Be9fU176YAsc6r4JFl2&Y1^T$I0_jTp#1Q!Q$@Na>YabIKf{yk2DWkWwfh#n4 zvr2US;Qcz6@4nMOW3lvJ=2|xcP47el-zLGQc7ah@tTWbs3VTt`W&lli{!%1%;k57F z0^KjI{?iX?LhQkVF3n$D{YWp-3Dew}5ji;opnF#@?OdAE-Oyq-;HgLO?HF1?!B-$L zbm_3t;-@F^O=*Evw)CBILfM;M0pE+05Et9feo|FqWsWz)hKL+1y+TkKixr`)5inG@ zG~j+~2;`D(qm+2W%sEns?$c!1iV7Suuf>IR{S!g#P0d!oH3#(Oy~*n4&kZ93 zQ~4heAM#iK5}njGtD<)Q-`xE_+O<|2H;y)&uzE)xflGPwZ&OB^ds$gk?=n@oDb1yE zU<{LNvc#Tb%tS%J(EtfvtT~*S3m1WO5U0ucszkJNzMhLEsJzkia+55wSYl(a`r^p}Oe|Rzw&;IyCe}E6I>W=SG z<5ELW;h)UNw?K*$k-}X>A@2~jgKr?k(&xOze5sNhcr9V#fAPirX1{qEjZ0x%-Hrb= zA+uNT6A4&vLOA+X$P}rz6L^54yv|xp6vuByDJnXIK!FYle}5E2Z~50ork>x|8I`lr zDlmw)=lyBnmmgk@4Vbb!pPUp>q`wyvprjFjmlW7$*JNemCiblK2kwB@R(cBrsD>TQ zCYPl5Ha_D7Jf=@@py;cat}YB!M6*l(~TBe%fy5^chrMBku_xxqp)>c5-Bc)|2htzu!xu9;YdZN+21Z5Kt?M=W)Gt4%-76|iY2uj>t=mSbuOqTYt&5yzEq6W>MYXr18S zpz1xft;FjXx}csEW|6V@#LoTr5c5Bh*G~AM1Fh55Yw;<*`RujZ?_lAc4>0$u`y<*B z@(0N1z3TESQT2)>aHy*@Cn0?U}PenE{!In5Zit5Ps#yoX;W8UGG3*2Swp7~Qqu&)UOFacVarT(B67NNX6)3I-u?j-9bC=zULJ>NJ)dGP6#!SjZ?m`5BS_C%aka34s+=}(-!$Fy{CarQ_nMqvSkKC>dBl#MgUhLNV4;@tum2Zb2FwPDX z{C52t0`_H$O0`hv$r2UdMpeJb=O9PIOM8XVZ<@6;@Qipnv zvBLiZ6m{0tR7KhOiu$eIWhFF}`0^8@jcqcdsK}hQ7o;ido0d437`p^rPHfR%7UAP~ zhTQhUnyBI^Zkc(rvAP zIN$4SK#CQj5!0`Ea?##B~2T&`3J%X-wq>E+<`q>QR{BO|K!T-_mHG-}*0(de<`9mq`7O z1xM+-W75oGT9&6ZFhW{s8h!##OHSG`jn6d~ATc{?Cu0ea+Hs@ZDYEC4(c>hn9`m1; zfG~!*=%|_Gd~=BOTAzNXIvO=~(RO@z1Y8sm*JyYCq)&l1uYy_5Ary5@sMtul;s7w* zAEHDH;I9jt*8D^Vn(}KfD&Mfe_}(>V6}U7@9MNw0d+PY`g(IEvrYVl zoVYI@htGM&H?>&quM0=t(kV|Y30g%|MKupQgmIcxFvqDaf1bd7qwJgtocQAzv@w%T z6mQ+DV<|LvdTR|~x6G?fHUboj9*b>RmWPm#S$a=-=5-Xr$j2m=COySwGd8gCZ$%)d z85lpF8&%@(Q?=SP%iPC@)+y2Ifi8`w-#Z+WKkg#66--meaB6+)&LeiR1%1A%z`lRH zomwEoeB07j4yCVJ>4Bpz$n|n|1~(460`M;@B?^q~*Z3J?K@kV49k6HQDW6MFG(3=g zU2C9IZgIobT~$e{;4%Gc2gJt^%ZtiuTbcWIO4Y@V`zys-^dl}0c z`uQM~rd{vm3+~4!q|yu7ok8DiuTvUM1^-t_`dbwuJ!k!dG=!Jqg8*q zieb<>k0F`d*OB{#wVe28@Nc^tY6f-hQrBIy!itJ7&?ctW`Z40RFb%z8F`4cts13=D zXpm7h)sSg8<~ly9k{WfiJF+cDdFUv5MojmPogJ%h!@VNzh3fpDNeDLyF!aWJxP;kd zhgtAvtGC+Q)F&P0WKGjdd^p^)V2r9SJ3?1P%EKSvQ6n5S{nfzZJ!Y9HCeciO!7omvd!Y!2>& zfW5&EI}kqpvb~7aGdgaMD`rCrAP;KA7t9?SglGz`r5eopp0Dw|+%O^-#Ap1^0WUj4 zMOwqpP0lV^*~uk=Xe&vPZ|9RACccK;w2-~1uPAKVRo6Z#05_Pyf@Mwt6up?2Arl+H zVyB=1VTNYuGdKXey2_zaH~G!^q>!+>grVQy$WP>$g`X@enyf8xfJY)3PQRL4|3 zphY(nr=GwTvWU&(_OCw2k=vOU6*l8lVFN8q{djMb|K!mj_=oOghDC!J8+_XYcQIKl z=A0`2$9$xr;i7e$v<^6uOtv?Jl7mkU-8c~O0~>%!ET4f0&1s6U#BzaxuOW6_{KUAQ!n8nCDfyPofWBE1_VB3* z0%c!Zo}70E+P6RCKX%1+VG7?IN8uT+SJNIr+nHJkmv%7Fd_3A-hu0!r$INu+ zf|F=^qn0ln;ko^aqu>y>a)2Kdf(jGxfr4taYZ2b?uE=w_JWqP+4~63TBLv%;WV|=Y zN-#>i(c3%;mp5}!>H=Omq@fHw4FTpEav{jFCF#LA(tAY=ikCB>aGm z9&S2l_CD+v2R@Uv=*7MS1FELBvjks=W3miRX_?nsqC7lvq0f(iHD=a}-Cb{t@9WVWDs^ zl(}uhr-Ys8KcjFJNm2s|S5!OsC7)Y_fy6xNBPbv=&{ubj&WFyMwRA#|b?qvCM^AZ= z#`vv-{G4;y05&}~;`*vm%Qs!xT|p+FxhDb(*Hl#0=(Is~UL63v z<*?aDRlLJLBZP~FeKlx2D&jt1ywUp2t&>U~ts2%Iw^J{5>~_eh;3^zuYb^69$)qn z3{KAY1`^N}9W*8cj1Kmp1q_+o6FDsDGzj9<883PZ8q-6ay5)wi2+>4^1)YQ3t<3QeP}`cOIkrhRK&M3Vu(tr=86 zdNgevvhc~d#SYeJg?Gt+J?H7s@joTnHD}qYM7RQ46HxBC1_vnFNwBU zo?FcAxlXX2aO*%leJqSIC-`e1B^tUJgS@42CRnAr;cJ$$fq<;K5a|y zvsONps-f7Y{R%MW@%TS`6eQ z8NF&_VUWUmABVWa&Fhf!mDh*ws19uN#{I~2#Zh)tO?CVs>Bqb49@HsZFhdsvl1f_; zKmH6mu&GRFX5ra*z&efWUS>HF{EL`?c!Bhu{_xRN^C$XasH}_Vxw4c=K!`+W`+*8rr;vBYo6< zI%R^HKhtZM?rN8qD*zV9$Ntyl4EzsoKPHb>c%#8J6Dlb(XAB8^Xzx5HLwndrt&Z98 z`8JmAGYF^;De#y%hlc1_$>-GPa3&?g2kOe6oAOD@>{G%nc*I!9EcAIGxV5K}nZ=Bf z#6Dz;6jK+#xtykURRCnn4F9@c^H3otX-G^AcOA@U5MTCx&8^hR^Et7-$G-}x(jva; zpr3|D9|@4#BB*hk#C!oO%0>7yY@jsQ7f;9=7h{cI3Q8?F+Stb*9yB zuzeUSnHrVXd^s+9E`1W`uCh#Y)}{_)Cf}dxyO)^w+{pv2zrXN^wujvg(wS=|YyS8q zu&!e~MW?QxEA4|8&2(lb_hmX$0d)+%D> zam$Do9n#2a*fs^j*eE0T8;9Nfo~fs*Wjs9a54f_$8H=j*t8Shgo^L?g0-}0_L^or| zo$NI9`j6J|;3g?*9V@C-F6ZL;2E|m`zj2+}p#HKVF>3fig&bMbZ$Ggfc~h zTdF*Y>MiRr5nVKawP&lpVW-e3KK&yM9d6&TOV#^);&g`yB)FC#mev_rn~?Jnn{!QH ztnCm`1w1dQWM7DcKNH+Ds&-rIp(iT?Lb&K--L)dIw1pn1MrEqex%TU>pujI42duU* zN6`g5UG`8THRkD-n1x8ufNo~Bdw(c!5#HVe9K{1dj<8|5ylC>n#tZIOfU1e9Z> z(6#YYSso%X?N_}>Vy|%TP{?TQm;S-Opuha_WDTc}XM-InbaHJ5ve&WOFW62Bf=|sk zjlO}S!+ZMhC`^4%PQ7o6H0Vj3JL4PgH*9`y{xThm4rd#zV%rlfl~FSPba#$5MopB$ zMjQKLcohoM_vTUe9w~JD$l($HUFeBY(Si+Cp6Py4Pxu2@C(8}!N9W*^c1>qKQ_MmP zCbuTf*hJ>Di_s(%k=sGgF}4dZ-Ei{0u$~FdX4n%Zu~A5sH$Ks{wBb$1<&Hx9*f#(m zJh;2R3H=)`@0vYDck|n~&Bjz32-I2M4gS7JUEJG@*eaa<6HII`1mb~#b-?JhFFzUx za@O9=qk^n|Bvrt&f5E0hCVtKs3r$#_hE0*l@nzxD`dc$AnJlQoy78hdc~C$DQFX?@ zUK#MzV6fU$kKl~y_$4eI5~rk$6^-Al5x&=|hQ1O`&=Q^XYN8mhMLg9w5mZ{phjsb| zKYUP2uMY!a-&6(SzKbzDYzFvq1{mel*^X2Zc(%iKPG*?TtjT!gsB_1wUtX5i`KJwuwMC9rB7su#i2cDr5spR!6GS(liK1xaHdy`9uVS=%4^pX> zslCubn!%yXT53d{$E;c*d{E~J25Qn(JVV}`v=uuv3egorelUfGvsC()Xhrv@pIuP2 z1X5i}dx_o;r+WE&#~(!v$zq;#@)nRvHLrPnjSeR*Nfvb9Tltz_nQR{sR5@t1y)_U# ztE!IHt-`}qB#>kKu>ZZSpmS6)=xXm*s!7&zgQxk8?)y57=$W7`d4Oa`jlqET`a+{KE1R@1x)r;< zRd5H6`{9#S{z@@dB`xCrhDLnVhx_n2Lh{D7gK@w?&Qx-mVcVwVN5hz)76ZGGl@jyy z_vWw*Mg6rv#~-e2v^Z!kS4V7>xd*bW7SC00r6>MF(H7@EG5|`?>G&-l(@I1!>RM+u>{~CdsTZdhBv}?q+)*-Jy>7MOw+!ywRlq+^nYxym3*bX3vw*(8 z)`u}<_I#YDFYnInn?fBPum&y#oPyX9Wnt_wH}UQ>rtMZ>xT9y#J{zRTzq99N<#p{* ziJ0Jh9TVt8aU;{M$c;)%KbJ?NbxzLmcB2mC!<^H~mgAk@u?LDK2f8p-eG;4)3;k`*AEtnJnW}*M#Do^Gl zk*;DGK0*De!+{KE;x*;61U3pB!HzK8u+;<6Qtuv31y%|k+McYXc&rLlLYJD07c}UV zalR@EuW)b-L~kKUb2|FXWXu2FO|y1vGV z!TdGl!CPS{7WRUx;f6Z{D329osDWj0<&&vHu9v;hjh~V{fJNf*q*Dl;)oVK?|_?0|PDG)&>4@C411>+F3>5fMYRpW9R+^P(li2kflQ-s9=f|>`DQPB zwB6nWujtPt(OD23sWHmBbqj4PHRs)ly(E{52Y-S!Y9(pt$^`zv_9$%Q0dLyV&lY+XRxcmk=k?Oy4~DFzJV+X9*X5` zp>XXfkbImpF*sY>IdS8y5$FyPgAUrc&z?(7WPI^zZ7=uaba8uK;op$slVvz;!5FAEZFj0{K~D`z{WL7u75#@|RLI z%49^u;EcImWB`{vZZI9aEmEYc$E)oHZ4M!<&wG&cEC0v(2j_c?`v>-`k?%dO!_CDR z>n6mI-+Qp%8_V13BSU)jZkPKb$@ZI);r0PZXfoD4;;+=gyAI^&OJ7KZuWhTrv+3bS z&UQ)u>mbnZOL#k)b|WGKsA!i&sgE;bq#b$uk23+iJ+J3bmANMX)4Uxq9i7S6=_octo^hN_BWhO|E9Qzj9zcdG{ z5Ky8f7n%<{iWmO?u`F?WKp-X{m+x*RMkoSX@Fnymn(s@jJ>)@(?DwzdUyn%fNURwM zk(JWw!@~kS<{C7FLW4jnHx9zl+WgnRT z#ws%Wx8Z9QSzG5Kl&M9OvtX4a`2Zwff$CM{{S0SPaq#`wV+%WoR;XxR4uAjvzDtOz zw~EAF)Y+ke(z@Z1e!OS~h5cfcsQ%gfwW10u8K^G>kSR3vW!rj{DxUDbS$pjpYK*u? z2@KX~SkE~)TCaieuTN?`vRyOGfpdXvyPuG$+NwIOFZXm+NcGQ2$Byoy*MO-GhTaE? z%F0*hYH?$1q42OC_E8+W9IjoVW3}4;wPOtu5#%v~I|MPj1I$#r>~(RB32!~z{1Dfp z{b8onUB&THM=^`_NmV@Wx2^1adupc@On9`Esl|!QA=Ai}VO_%3Y?MdvHo=AgjIg+q z-@?BdV+QK6A0EN$B>U>Mh!p8y;)3Rn1VySKF;MD{=nmN;(n#9Nn;)M26egA7ySq!o zPp3>4fFtb|{omtJVSXyxAG99r){+^z{p!`h{yZm9zKVs&|HVtTym6}6WHm5TfrVwa z8kh%q5J@I7J&GfZraz`$N!TD;`ffpn?4zj=!DZ+%AAmna8m=;(n$fouSL&n|Wow0U zcaB+tEykdB$lVu7C=M+|w1d9R9F6ch9XT}ss118FX{s4)lPX9so?Hiz)U!K_gP!w?qZzIgzfFylkQ@~-c9KbjeQVJ1W@UvHP)uTv z-{seNg78%YT}T4?A=&|!5^=H$>N>XO<*7x`hD*Z-_n1K(z;f`&s#UFVDCn6;ZIBo+ z&qE`}g{`6@EZ5xDyj-gm92*zcKHaId%9oF*ZOXrjKU`;^MvhE^)qoLaiGAWa!+LQC znTfCZDK*gXUs1-(l8|Wyjr-lnRXkX;Q`Cm1c6~k2SlL zv@~)ek30>L%|?mTmrEt;$8LX`a;ezXAo@NS-LXs3mR3J{5m7#_`PX7~Cl2BI zdk+ym0yZ--e~FeMjpsJ=m5YBZ)L_AWClq0| z<8Xku(yZK}_pbwcLfrktypzR|hs1aAMn}mhjfZ*+bzQk>)Qoo1<1|AN(Rx^V<~nr7 z5|M*Fd{|Lz!GaHjC7x{J{PfcJG=d@z>14xR`ObF5{C`o^H@%CuaKt$Qx;eyaJ=^;} z*X`;xFK@cF$MeR=lX^vvERaD9570q< zvl`W7V7$*IiNQQbn`8JA*mRc(g2Pw7brdI$m+es6+EsaO>tA>G6=Z36@uy}PU>qQX zMLk&^ysAo$zELHvm^@kBOOb*W4MTnC!nW(|L=6c+3KVRlj^D4c2E@Z#aSpB%pLnW` zFANR4Uh=8 zi_sy6aX0NQ^FR6g^0+*3R!!wl(J)Y+c>ZJ$WjlMr{u{?^+l0e)aU2v;DDFu_jxpa6 zEdm|gKRcZd1Nr!#VbTn+P(+BX8jC79_;7CxNRPh%y6KX zZ;Y-m0_!$c3u>W_!o&|2w*3+^st{gP=8v9FgX@;SU3^%s3RvOUBaat*(_Qc;?&7+4 zS5>hh$=9q0NoEQFDI&gXgF2oNt3oM&tnVc0APgmDx9@58XqJ3}3hucwi#IKe7r$O) ze2-Tu&py9w`In`llSRLGrKgaOdhQnHnMJqHD$1U@XFDDf-o97)dt$%LeqC$;_tAgP z)Yj!^I`PNmLwi+toA#*c&FBOCVW#wXk8gFWNHtn*_$^0(jm;MUHnpCsLAuWXUPrhi z{H*F%2SU=dMyl_wLR$W{>}KC~2Kz&mv$BF#s+wK8>Dwj&Ou9Pihj^vWF9q>;+SX-w zCp7^-L7zA9K5nB@Kr-w0D>bS8NPk%p7>^oT$7%BlAH^_R!xNtyg7b@FRTC|N*fQWq zWdLmFo3Q$ZAidiIwfkF?gN?odIsdA1RtxTw0sR0%X%lVqg*>Qez!xL{)t9JsDp!Uq z^o}>R4r1c6M+!xAt_sy5QH2;y?vWFbXHcod!UF1!a?}5PhA7+8-4Bq}__)1SRu4vi zwXG2Eer2cIwKD^$qLQjm$ zTq4JWtkY#~M|N>P)~(|Ob?83axRMu)C%5Xz#F7;Lggo@gIx$e06+#l^mf89ngIkLR z0P6(zWn+8lWs73omHc>MaFt+q0+m#Z2lupdoTmd}R4;ba1Uf_$TbJRT&&R6;soDC6U4gPv7cg@s@fNGV(olj_Cx5II7#JoUGDc)O{&zmSFaE!m9jAD0V zp*vnCbpv@=PxD0J_T}2W??@}XYU=si@BZPP6T0&8`oa&fWuo~*i{^84zU+r&KZf!S z=XYx~Wc0Bd=g>(aTI}y|z>G>ORY-a^)XsU{kxSxHy5#d4wpLU9$lH6|9YQJF#hd4W z+sN*Y$X^8^IH&z1N8|R&Bp=ep;-qfQ>ZV(LC?fe@LO~g5t(D?s$;g6Q-1MYMQ#3!{Re7( z7a%VCOau7^roAb2o!)}u>ky2mUF#!t|3_$_ckk$GOTWTm7$spD5ATg#?{v6VhgbhD zt|cExU2cga}*N-N>LdE^o*4b2cirSUJwn0$SXiNASdfySauP5YV^`q!b3ukFqd zvx&Mx0D8l^)95yAgd4d#jY8F$wG!jG?ICQ}l6cCcR{>M;VAlB}Z9;Ra_SZCcqyZ$J zp8`0+&QclQJVr4-LyK|KGQz=APc2yu#i;Jk z-|+P_zXq?cWr!g8Sl;;o8C-R6J)N{mVX}VT1mZwDoD+D5?Ql_@0_J3m8%37djj3Ra zn;?o1uqe!Aa#~?jRXrY7hF*W1@%FC^t-ei^^+0p77CTN&R7AaY57xu^qgFh8NDunp zvTd?YR>{jBo`O|`9c$hTB@pweYIAgx+I%PBga-v*Wk9DgqIgZhoz$RDxDusZ3A^eLkHZp4sKz*P0ndet^)Io z)7Up!b_nq}l=t55+FmioKTgTzeaG=LU`^l5?T~CMok|#P)++ma*_4q2r}G$P9vY+|10e4> z834a_88xx*D36{AJ;k>G!QF@;Ly1IeN z#hNYXaTUDTOOhotu=zNE#`e2K+{X+>ibhO;_d;t$|NMs6SS&1&7We&oDKkB#Rj)BY zeYX&iaiDcUZ(tp9mkPn3N`hH~ZsY1l_Uei=Ym{W^UZ;E<1;y)x;o?drP?jDI+O8|8J4&AK|ZnF7!u)2~R^E&JPIQbH-}o^tbhVoXf(a9az&l+L(GhH6ehG{-;S;BM)%< zdfCOk?UyvCq?+Uw@S;JtR(6YubVqEFQ6(z7!;t=`-0{QkG=aznKZUm*t-5a`S-Y^1 zAA)O2Ic$s-R1#HP6G_P|smvkJp|PMW(=gCzP{P-D;d+iZ|B4{!=Eq z-Sqqnz=pdipFhO^JCqiC{FM-GS($V0EX1c=5cl@R{K8W~&|^dvzxt=OVyCa>@QR5@9%}yBY##i{ z5g?~zh;8*w&OY`o|)AIo*8M(Tp4JZ{{ zwpQf|hcC>Z)?vz7buFKAkx8XM8ImQzmTeD!Z_x(KX4?yhglwmxo9`cayBfi;e!ZkD zgdt+?9nta6SsZc>X;W?1l#-l#VbkM^gcM>qE)q3x7nhGm)@mJT_FMc zXm527hOcj3CE?&jEx`2N%?#S()-C*&f(YpK!;x_ z&-sQZH>49Z4-?cL&U10SMp0nA(Ml8-Tq#;p<<`)P)1n_y(+zySel_;b1DcwZSZ`cL zq#iiK-Z@gpvD^||+cqeQstYg6c~GU+osWl^Vw5mbHsh5Bl1stV_5X0X^I;Plpf1c|JQACfi>dH+nv| zdHPvhdLF_eVhw}nxeY#nPR*KU1|IT=@{d-@XTv) zu#URZ4f|3`qi>P!<^5G%?Jpz&8bOLnafQM~uw031HF_WGf(edAh4nleCoShLSZ3E? z7FtJX14n*6`Px=s%E&l>}|(k+u7&e7XID zfiGDhQ34-5(VdmI$_}@A8!+8xN2` zZfO(tcM1OEV5gRT@uSz3V!{8^(f9bM#l(e~HgkfrfBNH7E~1WZhH46k(2&=_u?qfM zIl)nBUD3JCYUy&=W8MJM6Zw{pH^s2ex6kSSkJ)M+=$O}2t4Ke@iPu-s;x`U4bxX@| z%U>(71Iau6bPlgh?H*bVJGECp$r_!Sgvicm{*WThF4Cs*qM(#lS3f{VKMx|YN!`mE z*|VrZH(kxrMABH1kY}i#4KkSXX*v(l_Urod{g_uDKm`C&s$o@8S<~WTKigvX4HCa% zYU;9Kjcrd)fy3QOex*~RH|C2q)27D}RGBw*BYsabnxI-DJ>4S$ z@OZyr2mUld441HQ42jd28Lgni*qMdfET{d_#J1DIneM(w)tuDrSh^vS3I(^PD?&oq zOM#yqB;0$eg%51HC^g*#5E)r@kIIcuPl&C8${cB7n($tE$8P`DWh5k z)tK>R#YBOw)4wnnZfE98k8n+)#Nt8M;T-)9Ry+yEBDx}kir}!$ z^8QCe`lfP*pa(I$85Xj1;9YsI-m}&cDhh#v-D>@ASU4B)%+Q-eP<~0^sH;U zhEP0jTKBVJGTRipptbb(=7(7Rf1?F%Qv+tHm~~X>8)n9?zMa3&dL=*udh_rZ z!;I{tlb$e3u`y!FsXh?~-lllvyEU-^1Yp4$)!=zTa9%54nh82Iv-ai6hHrt8uTzv0LE0&m%#hQ9vAQ{< zv0|G^AG`vDqOj?XU!W&ne3)xS9=5{i{yzSsDb%^FIj3h=hH@1#3NM2oB@OLGap463 z=bos2Bg;Z^ADjwOQjDLl3Sx{B8FZQJWFx(D55-k#%@A}3j7EVg(w3kP_tnpD$4~ZQ zR66-o&V%D_$DcZ5kWji$`tZGG*or3RtOEyHt*y5iHE*lUwSaJ^Xe`~HRjH~>_*@Ir zc+>veHUTLpl*Dx!4`PtDp$3;smgEObA~z@)YyS(5evOov{VDof$D1Hg<%*!?v%!=R z>GJ}oR0!;9Q6t$}#}K4N@uGz=NNlO2EwWZKkEnfak6Ny6Jox>vf z7Qx0Rls6nRa;Z;bzfwpnbiWbR6ETs`&>u29h4Q8=%_7>!2YuBE>faB^&(S`k-{GY6 zV*|O|-^Z3rO?>4zY}3{JX(l;3%fXZTN?r#{S>wvqx}ux0L*-|qfJ=Nc#kdi#U{^j^YPPsDLyqe?mv}jW(Y2+)ZH4GQGjL~$@>chvL zVU+IX>!Y&Si?O%VIekj_fA_jf7>#DgPxh2R4C_P3A6gtn+IA5+q`_tCp-@mil})?< zoCD3un;(Jrf{YR8inL9csV)1A5iVhlVry*0yt^tcJu)GY)sIR#dpRz!z|EJ(2(NMO zE_2;x(5a^PZ{sQ0n&^;eO;O$Uf5*|6=Dj7)(6RqOfB1|HDE8>`1-_iTaho)2o>jon zJ@IRq72$tEQxg820dm%5ZO^)}4iNdV`aR2#^pc8qqzMDP)ZttOgStZQVBlYDlIy14 zU2Cp`fMb&<#%ec2u%%b$+CJ{HeDxqH>>=9`I(jNl`_pb9VWKbvBqrgttr)}u7cy;< z!o4m2siHDoi?|uF6nBQr-Cw7suV;$ukcl?b9!A6|kmpeS!F(BJbw<;2f&kd54BJ^P z;e+e=eBRL;ZSmnjPDAL!aIFhJY0@${XE*XpM_=P7k05(*8AmS;de}sMdYq5nR*p-f zKnE5co&Ag$$tVZXz>NZ2GuY8Nhd2jdj9*)_Xoe2UHSEXF9Y*U6xW3x^%Fr*QAXPJ# zqQxNwR81I#;?JmI9m6IHA^%mvQt~r32TEKnxB-T#8`=7b@`Kbzr0NL^)|!GYMF(!a zS~raD!LWAI+#VC3BVC2noFHUY!E83)^u=Fh&Qc2K^=4a{xtVeLnQp&-0_H8zoc$x^C^L8XQ$R`gq1O2{D>T7hYEPYq7!&UzUc}%g7red3LSQ z-;4qwupQ#T&dmId4lb>fh$o(>3p3*T^`@@ve@pY@<(~@>w`wRp@1qJDTJg+Os5s5M zVQ%zSmWfC3Uy7)c1tWQ5hz+qTHIH(=+3JC+VgX;Yg_7GQNY(Wn)IL{IM1o}03~s{+ z&wX1})#BmyT2uSBf%F(&f0(|jhdaP=Q3YLgP}n_?9!&D#x`nNlr-0A0L+D4gf}z!f*+)pz!=gg(Eej-!iV**XMAeX|<1V zs`X01g?~D}?VdPLu)lg(dPOdIY zI3nwet{Q{kQ%lJMbpk5(gc0b`_xBHzv8EnlKSsZp_i^{CNB_4SW& zBI}FD-2CO{u7J_(Y07vo30=HNQQf}cZg*VT4cc)+p6ySQWQ!mD0< zwi@q`_W7;wSV=#PKhjt_h$ZtjMHc@~8vMBa^GBY_*+`GP3l3@zO}KCUS~wUq;88z{ zo(srznDP?^;f$P;Rd&BWg+*ziqzfR#BSZ|m?B_0mp+2X}Yq zJl|P{$&;=C?iNZ1#Lovjl#b7?@1+uppjnNdCl4xtbv1xm6kX_xk|V&+&z#=n3@llp zgT>L(Y`qDDR%rva%jsC9v6WE^Rl=9RVt!h^I7`$Z%340cVN&fjh(oGM3@Ib*!nITF zT(LCz@Mxv*GQ%aM5j*lRthC+a9%mw&G(U7;qomTY7S1py;|5V9j$zS?PaJE~Ryio$ zAsj|YPOyujmNb&Dyq)G)fBn!zWFDpsbeBXGS8g;3JVO5w}2a$>NZpMEHNJ6N$Qq#*-i#&7I6Vgvu0@4;eR@X1;Hu z2(%aJNgJbk}=reNTpIO`gJ8iu$h;*>S&ZAyyZw-~_YR=>s5{ zfR?u$g(Y|;U@3}`XRG*>QKtb-N$J4Jq-FOv&RWETQxYEIh_l=H=FD^rQ;!0y4UqSi z_JIRekV%*db3BcH@boTi1I&Bk8BnD{tvOJo!|j?bk6Ftd8vMVg6^fbf=FfciBR*G{ zWjzpnhC@qc^W8?`(}cKUeJDHyTO%wKS7A>Uu;~uKEj5fBm`f#BxoDXWCvSB7VTzf< zW;E{0Nf+aQ)g0PP53na6-5t}?nS4H#c2;PVU0nq&v5Yn!jGTcj^{HYl$3I>8Jrr8N z?-n2!(EMkc#r`t5%NpUlE|wfU4;AA&3gA_efu7y$-WmqeapyTl)%)ny-PRRRIoHYB zn^5g%s1#ga20wUB@_ujlHtqR{hQI8AlUYSgygi`5&$!U8TYXYM@dav!$+Qz8-60uO zMEv`V*^k0O+gJQ#mkuO(zWB7ruhv1#Br>A+$qBB4iP$2QQrHFcqYSHX-HF{2_hgd| z@uHIGLhHe&nn;}I@E!pXoNreGMr+^J-lju%;H@!F0*1rJj;)XT69W&aP*VOxm7c!{ z;ghlpx2~iwkCahl*LHq#=@dd8c#b?(ByoCI?CN_xXMGEQA2#d{xOi*2?0R2*|7`F+ z3i8C{drOZe2|U#dN_*dksQu~rG705@Dit2NiO`KFgK!fv@ZaSimGft7Plh2?GD=f9 zGY)|0^FOXCs3o|1>a%=~4O#AXI(#%zsBD61npUZqAuR*@3AOeLitJJU5X6irr{I+u zjmxrfHJ!;&&#lS+bhY2J-BHAEt*-c1d3~gd16(!@j@>$W^fj=Z2>Dx)GPMV0AO}Be(D+r1@>;#qUF&Z?5G!ytjzhJ09%9B6RLWBPl+NB zojKuP`gKoEa_YGwGXiKn%DhbQ#2c}q&xWT6zg9!WK_-s*1_8_pegE+h+wwhl)djw^ zNmmGFvzivh@9%563i-7&0rxkXl%M|nr~_cdrJ{V{y!*l01J<%4&BXxq>+XJ_b2Ri1 zsnP+j`}^oG;N4#gf4Y9(v>y)-wwm~7cgF#?c^jf!hHAyIoa$>1QVe#Vbc(*rm^0g+GT0)8j*IR)qCptKj6cD| zuW?}JC`g;35^=e=I<`NA5W#@0>i4^yus?5MOp?Ut2PDz#GnvC71ieW?P-F>b-6-4R zdF-aNEXr;B`}vlWaQJ#J$aYOpLJ>ohpgfTJm~Z~N)8W1++pf-B2MfNqs5`p#r+df8 zC)gj4+(2*lC+_qdJdFwpV?=O)9reyZ$saF|o7g7|pF#55ew}}wErj~suK%K4zDI)8 zy5e4b=v1CNYYc96ujWt7?MX;i`k|W2mEA$jQTC~Ft~VdSJUlBckcdZ|LuV*?xK0hZ}CDo>Rp(t`rd=4V!aqmQ*#O0nSs7iG21 zw5UFZ5B_So+niBNWhP0D-6v`v3fh$zS7exh#jEK{&o`mZQ&u?21wRj4rM>Av@NdIr zi)*^s5pT3MDzCccWDY-qmgR(qL^Ui$0DDH$rO3AR_>iM#k_cavJpoi}ijUX{67FyA zhR_KJzA7QXG~cCRcHL*ld;o7tX#uG32ghmfhS9mvoLnu=?bdvjS4E3W+CagPsR8#a zfAOG)rB2oV-vM-qp|3dUNqyDM&n|<>vS&%#5Rw>Mg<86kv~DA9O;1d?g~sd8yOh>1 zuPIHh4MOFM73&exvXgmr3UrdC$*>}l22QbSL%(Fq{#DByzI;RC|77v+CDT#P2A4O5 zi4Lz7zt0c1kY+b$9_AvXvez2iGg|ot+6xV9X;MDK;$gFw+kz|`X4e9+&lPRf2CB7( z+1J%rTh)dzZ!+Q|z_B!-n5z#tuIXH~stZuE^oz~G7>^M`N!n{T@D*qe(y29(tto1t zXsIvYmj-+HTz%*AC!V#w=!oQz7?LV&N_!Y_u-(a-#Mdz!4yve~j8W#U+BnrPE>k|2 z=WawaTce*z-~!a2aKsszgJB&0aKS4Gyz#vDZ1T734g*@ZRb9*^zyHAoe6RSbtY5ku3vR0%ZZW-#Wd_ayPqJUqAL~)uER+y75F$!;ziyZxvSW7J(rB7S=3R$=(fQ(C z4Ja}xKhviO-nsf-?@wi|hA+=rff=F^QGnE z_r`~(D@kAY)8y{E+~b0cH4MQy@rUe?OZf0jt-=2K8w-E4M#MW}E#Iv9x5g6!FNpPm z8P!h3mwac%6=#5DB5rhpi+3l>uW_!j6tW2{Of}GG+e*ORpP``A_DyQ{Vc3`@j&+{d zkvVceW7m(*0W_OU;Z@3)ctVWaei9i!$c(&I6G(t(ZxKY{OOqOA(8%{eu4J}dS@Pcv z9UN8Z*W@r3gS^Ng0v1+t-rMsuwlSz~mj>!Y`(C%KrT3}?@c-7<#bwbybb@DuO)Kl( zcr#NGx3D{mpr^IAJJ3&imAO~RMcN%hAjBu|=a)IQTsSyMT?Sm;axqtbBp&~zB5#wa z0X%|!YB^YAb6EkECK=ak-;ghed;}q>rBuS#7>13l{yFRTA8p=bCN7HbG~(PvG^Cc@ zkJlJ#fup)T_vK4pq(3RDR8!aA>XCr7dax`tr*zZwYiY1(2T+Ao6W}rNND4+?XFaCof0-HR)MDX zalWd_$n*reN zm;@uROtwcNJnj~oZ45qxGc$jSY?BG`Sk)Gus21Qn?6t$$U+6Q7LiQ~4$teA~t@1%D zXxi#k5V{qfWX&p$#++IFF6F=*FvtPSXPiH->E~ioKO9K698LhAplr{6gaqZtM_1@; z;5e!GG77D~=b!_w$mT!y=yo?{eOcmsrWN;_w&~$o8YJ5ve?L#P=;or|8toj#BJ*Fx zGj;B;GTS{ym1ba6e%7iex1RNDP!HMsY)-AFr~m`pLmb2LDmg>` zhr-1mcuFO&&>SYV*pJ(uvd3whX|LiPrfCAGQdzv#fh8x&6(s$J`i~}Iput{5dB-JL z{cts`8eYqJ{!XjQruf?gy$>vUlNlIROTB-kM0;~T1e0T8Mt~V4YMz-o8 zmCdN-=Rnh3p+#<`bw{TM1teG3EipHqV zZ<@yz9lWCHeG&+O8~hItv&6V%dicq)sz(#U$P-gs9mR4CT6LYHrg?M-4XZ=n7$ zIbhogNKB_D49WNmH?+|2$V1`uT4QCU=6)EMh z2y^K_Lz0YW3F6anYc0E5zDRd)3#j+g#gKaJm0{ z9opzj=V)%XOJ<2Z&oo-ke7rn)GIKja^4xf0C6&g6JdD(hS8bO-kwx^*!K0_fi3$O* zAOP-wYj0)-eYjUUoUqw}msFj#)myEC8-Mb=4&&W@&Sa3_w|7FzO44Rh^2-g?OA(KCI34~-VBZRmxsFMhm)L} zUxM;&=mn5h3)1b_s-SDb=N5~>IS=%8U*?lp0#PtbXM47VeBK#E#*c^=H@+&a>+Sx? zi~T0_OGPQ|SI}ofdK1?1S#Ir~)BrmljmNhEz7T=p*SEi6A+e)^;<_E0D7A6_V6qXx zo7+j@q8YFY07!snCJ6Rk-S#0 zmt2;Wgm0g>-f0?_s-~IN{I~C~xd>GQddcAcspS6OS=RZFVaoqac+(#|()HhNWxd+VQ zLBvw4j<3oK1UctkmzD`Pn~v^{U%dkBO?6u6hN`kySg>FDwdct8o3oaEN44KOS_h&Y zBORR_cxd?AG_Ms)=wrA(+R(*$v+q0fOP06Dp|D}eahXsb_CNn^?3CdBWTx!tdwSm> zpa@y}R=qy*;QJh*I6xDfxod)~r@mN)(hRrv!G5kUNeqnMopdqu0ZGxES%TFIQJ`+2wJDeyx~M3xct7Z zMYz@FVch+#g@BAZw(-k=EISlo!=~GD4e9K4s$8oHcU0o5=i`BAhp8V8Wd@&EyDDE> z-wdu}1Cj=7QPIJlnk)gG_y789meTJ8yY_!)9G?R$=Q^vM(>& zwp~a3{{9tR6o>aEyz@C(2UZt*hO=OH3GmxIiQ+PMdUx-`X0 zWjacd{6DEk^p-V$TQ?GlzWK~X_6)91M_nt4)9|>}}Ind|l!n&$?VbwyQA#i_YABqo_+p z{4+OIm#0n=USb%tf?oa)O*sR8*)WT>^EYeze3bSXrVwHiLxJ;nDRBD}9MMY^GGO{& zgqh+(Kmx`X&Y@BYG`=)bq8BnwVH*+{MnP8#o>xrB?L#Hh@5tuCFIX0R3R!{eT3=Poj(# z{ua+g^y-tb5oA?Sk+SlOFe}RhB-Rj&X>KG%tz^dP9^O|KXExYu`Sz^hoo_TMYXs8VD&c`Hm9xHV&uTRu0p@~Cb ziM8i8)f)wAAaIMU!PI%Htko6f`VR@51-rvr)JHbol}rLgL|X{M2`O^RZmjQM4fWP* z94o;)r|@Bj4TRs;1RFZ_4$h5UffyG~hZ#_1aaMSLATTIbeDGhD*{iU<-7YBL zr1I1+eOF2kNYNSTl^Hl|ERu)>n|yvg&*Dv#1r6ikcjIs{gb-E@f#t26mWpOK>zWaN zUD4BzzWG^NXst}-@sR^M2{q+)Jeibqyg|G7k|JU&$Xy19H=vQjl06VipNEDvqc$;} zw3H%4hFu^!BjqP>9qB^`)rwFGUDbzTQ!tp&92^|mV>XVL6@YN01N>=p&2TPr-g<_5 zZc((lz%iqINN-#Q?|?+*MjtWd{xS87t9~M;6!KwFFRexMa-)SpJiL`c+$b{gL_g^| zY31EdGyi99qZRXHa0RrDcBU>@YpkZ#C(m;84WS9kf>TpK)L6vW(}bQfo%@c?BWd56 zkx!E3WBdMbq-Bvx7sR!HE`Wl$B21ZIi;@b zlUZb<&^0R@;{+mdbT)cHl#Euo%>F)6a&b%whg=sS`?6XRj=MvuTS%o(b>+d#?ZWi1 z5;qtsvk*QV9@|>Ir>#g+!7MZ+m+_-`d)TyMZ-mvl_fJKt8Zt^nTsMz~e$V3fHTjsX zgJ)sw9EtEd8KfJxU;~!YPsfNK3(1~AOVLvBrP~F#bK3p)+bf()Ll^&p`x9atgT$#R z$mms(X=0;A>&h)9!kODqnWQ>Pxat^(`^N*kJ@pVnhF!U2R$*^F)du~0Y)D&eU zOR8O`>KT1EvkvL<@x@FB56|5<8y<0Hufkfx9bK4vmJ^q6GrQj74 z#Ju1W=>78i&F4Yzlwr6V|18I0;lqWx@c%B_v-3zrA@GEjNw8wZ;L^-9@_z&y!Jj;)f}&94 z>P(jfdAml=2a}7LqRu}v8Ne)8fiAwiUigY?8I-L%5c?MF3-9p+8imJE&(uv0i>1SG z0JP!%*@<}%kD5f)!R;BVa2S0&lmB~0+hikK-1@B8O3?ZK8^nq=Rb%o}P4>AC4y(m| znLJlrlDXNnh(aF0DT4NSMlcg-q`_J_b-rG+<$j&@C4oA1hODp?p;jK>q7jV4W614o z#2jy@7yn8gKcv;)wc{Rj)ZF~UL- zyd#uynC+l@mz!KG#%-k8?2ibTS*BcRhW4*8%P_p`1Hlw+t7Ur8Wd^7H;tkRBTY76c z-E~J%oEqL2&A71z*Fd%&uGd50kw(#A!)p%By7dl=#Nj6~$WyfqA+orcG0;!C(JD*dY93qcQK+b=;3=43TU|;G%6a`{ugLS!C{+t&hg}+L33EM?hm`s*Q|LAgzwl4UoUGu9bQ3t6M~ktSs5A zH{zy}V}ZUf2~-OjDes)Ou%w{3a;86r4r>9CD!_9gm`w-s85rf4!EUCL^X0}CyV@UD zQm!w#u&WWtX-%Xo82^mUx_Qkn&kx5BrVrM%&boKIB4T9v)#=VTQ5Zr)J8_TF7@K61 zM@6;+Rz0I&!k7tinl#E{6xNii`&|D$7p}u#tf4?pEU6ydg_RXAI5ihMWk)b-ps0`R z8a?P@HB`lVjIYP2Jgz+mg1hu1VG5?9uXnDDynJGwhhpTKdFn)cT}76KEskb=)Wc(! zCaXjf(wQ5F5y(^>pjdcKtbWV@MB|ep`CqcM_gpE8lO2)J82s_o)WqC(!LXnWKK8mc5iK)&-?RJJ<^^L(%?2`XL(iZ&bth>HJg^xqK1Mqc3 zM7RhpchIF)?LgiU(7H?$F1tsFw zgwE`hxH?)DD7sbHBM?GbW#ONhO0j23MA7yFNqhwzhQWwW}UxERYsJ9 zud;W@CbD#2(mgOZoC;DM0aK#=4|!12$dLee-J#M~3Ni2x`yNd!jCvt$p^O6)k#rd} z?sAnr)%EgJc^GjCt*D^grOD?vQ#8z9I{jeSss>Fi>H6Uk4KHDcm*ThH>B7IkZFWdc z$EA*Yt*6$9e7~NET(ExXTuUfA;AasmH;D&_>t)(ujW_f>0Z^#7O>im#mG7fn$;95r zR4^0>I8g2syrC>3Z$jC7lp|rS3wzpymvG3ZAl-PVa4i%OevRIt%&sK$f?Py+{>TlM zI~r{F0=E{#d(y%CUxGa?2K8Y#&tT6f5-TImE0&(wt3vQtZU`7JlV0?xix9OgAg|Uv zl@q(X8|v43uD;*O5Ir$M^n^>qp_j0|^M{`~;#;xNy9bLp{<&q2cqft<1x2Z#7h12= zeSzx!o@uv{JG-XWQ>Xril1LqpksMn%mqBwoQ)voP1BvT&&pT7+8BF*P+KGr&d;ryN zazVYnY{VdQn!34Hspxy=ScU@87CtSmglyk@d$dZLFD2DDM6<`_r&6%&K=Am<&j;-Xz z5Jo6V^xnn;t=zK|^?M+S1z#vQsH0>!fyia%81UAEZV^-AWq{s@aV-#xwe*%Z2FPRR5zIQ+PWI$;l z!Fx66GteXYFcgUFm1wrs5T1YP6P4h$Sb3=j7mdX*zq#c`jk>Jru&V~E9gUa7q?&Z&8D>T?Cu*9zyz#U|VlwlN`uzYwx z*-L*bcM|CI*WD%wQwGis>`wFddWkLAbq{`HWkIxw8%t_5vb3{EVUSV!5m5+lqH)HZ z@R%1+_&7fAzw=gyBlbEE?yF)*v@vKkEVvGxA4E4gg+;U6_{OK!R|1I{8)<>B^CA|pbJg*e^t@)$FL8}6{*;Y_;M14JijXX=8O z;BSOdp&${MMj8PlJQ|R`uqnqLa3y2KEWLQCTBs&VgJv{8nM35@LABOgh!!&-8OxIn zWi{_-DGq-zKM^FkYI9deHo7JFH@&!QaKjOYPoFCP_2L93UMaL_OT4lwb9T+>XzA=s zb4Be(Ve+d#Q@StnSK9Gxj06qXI`vkT?BACw6;-sF*U3#sMH8@0VXU-~W`AQG0wzDx zHHchK*s8k|YEJkS;lP*Y6KG9ha?9!Smf}bToBCCt$NpIJQ%sJ2On%PqG;Dv6{0^T_qL|%^Zb6s z6S=zraUm^Ww~W`=NVvb&PNg^-7wNaZYb^{5;L15F_ZtL?UDxVlzm9_LR(v07dk*^d z;P`BQz;}e!^K@CCNvYgfg(fFtOJM1X z?}Q3Ggh89MM>Jhuc7Bs(l}(c9HHD5&VcPz^$uts2Oy>+#AGKqK4E*_Ih0{sBy4{yV z#N$pFPyn};tyI6jWc{pGZ!*q5l=McgyP@p&4-i-@fQS!1$#TgynZv6T)j9M;HcmJ&)w z{;R_^oH!cHFu#$NKzp8pZzjL)#5xnNJ;`YXJlk8qEXp5r1X@2^&)NLg9#1#RdV%iRin3mr}LN$%H5WhDtX77V8}^f=0gdQex`Rq=eLe|W2AVDyo?YLb(kYWOLa zz(bYwI(%hLgW>J!?R~n=Zio6|!JF0W#8Pl+D&tmmpNyh*jzbw?IevRrOz44|h<9hkZ^B!FB~%X=z2Rjz@Z>e0W27cG5DI#&Q`5js z9pa2_zKuHuvR{6usJJmyLS|&UVl&`#wZGh0v178-DVE5aY%<3wBUja6+ z2$=7Oq&Q+8ERiFNwjg(+7$LM=x?bbf2Tk#lr|Fs19ed6h3nLDe4<|%boCiJZlLpdQ zt@pbP-puEr}|v3F@HKBWFrIG*(qa_^=$bx8VxGr z;@#Q-b7GR3YKY<)u0P;lWgi|1|8=m;8QlEdni~ABw-3|m4-ShWiCfH;zU|W&G`Iz= z6Jde#nzytelkFr0Z*RMZn62@82i}BQ$~7=g@d;nKAuw{ z1AI`4P}<(_HL!azQwhmeH78ooE}qU%8{$hmjKx(2?e4eLpRhX;zhwwaNNQBtJfr?s z$o(fjaa2NKER2IP@L7>~s`-TSig^J}oQr0&JYQxSN!6%9zy+ENM7C5=8BaJA8XuFmqCvj`t`A6@;hDK}%cK;FVYu8!eg9VoWjRgy58)LY5zfv-VclLt(H z@!&2&by`PYo8?{~GV=1ZF;bS;b>)E?2C6qd^ZNo@gjf=c&%mP_)NBYVg24_L{rtN8 z!XAm%vS>v?{oL-&70Lg*iQd;8&mg&^vdnw>2k~e13)f=Q;P-|5x%GRHzf^9rl3+m0 zSC|>&hCF}Vp$m!yUs}W{vr?fo6*5yGoVw#U%fMSGcnFGq162;2qU4by!)8jT<< zh?FAeT4GRDgW1d?7o%+}eGDNWyPIMupNhKc1o96BM!;zSXqRE6quUX{a(wEAO`ldB z2PcB1N%zMBafQA0bi}2imysoq+8>+AvTzH-D`nOn@_`eD^qc*_o5q^BR^$DZBm|S6 zAVU1;NKB6A$daJiNsn)G#S46JS%Mu_F5^*x+!TCSfqIOW${fZb8q_R0{Hfh!=DSl| zeF;#rofhjY@cDS6I1wPAuu-pfLLhwn7yTbtgo3HMI4$>OE69#LJYSvK+zf*Wf)K%X zbznf9)u`*&p+^~w7jnk94L#Hc>-R4;p=l)^1rhojpo%8N0mbi&TjQsQFL22!!b^l_S3E>T}f)9o??_355-N)j3m#!jL5+J~q;Ox*;V4T7=kDVIIuS+I8h* z4Cp*)zHvIvI-!V!+c>#l51nm##_{WdkpHxvdKKZv*h;|2!M!l~>v`ukoqMrgK8BIt zR?dkC66j3SgZYqq-50U8#N=UOU#|1-zpjHphI|NT{)*2Yt=k&tmlik?OX<3J1bR|R zK=inv&D_60v0Ph(ZGIt#z{^gPkArbq$fkk%E7y5dw$=Q9q@MS7mrcf zv_gbHJ}ng^&dTMod^k=9PLzRvmVu@%$b}_%;N(n?AYaOOVRS`6`@!B2bbqBltOfyK zV#efFaLF+F*2Rp9k*oVfCZ0sfPFVzPqW>Y319J#==f$Ik$qc5A1z}pYQ9eXuDK3Z2 zS`J@w;KEn~{@XobnwH~EWQ`hj@d2)$TQuQJ{m~aC?Z=-SiIF2}%RBM;ABS-`b)%;r zQMHHTpuUIqyU%}Yhg&ErYQLcsqL20@enk>ygx@NO{z@$ho1PuWaLnuK-|@Z1g1iy$ zH1a_P2^}sneW^?M@jIU7uLbayGJ85e$vxO9=5Hc$^ur=U2pYoGzbZ0WxO5JoaFLA6 zpr?$NrbbK3su}5L-#XR0nzc7nC~jIVUnzZGc*s$FSK1_}HLMYQ*xv(UUn2t}Bw;Rrw8HLsh+-qJ^omizU40vel@ z>Q2U!r+kHuLO29@H_!2jbr$!7u*rwRB9fPoff>uOjc-(@gZsxNeoZAFTBqQ0Y^p_i zd|lUV#$>b? zj9oK#vbs41pgw|vZi!hZeEpO8>{l^xQEY~s-O_>Y&gT}H6DYks6>D+AhH?mja^{KarSA70Z}X;SN8;%~l#4rr)(}Gh_K%iN^Hc zFX-4_7km};2|X<$j6IVF-?ANlGU&Ee^+vjfx-KDroX8a#>bOxi*NzRdf>M?b`hF)O1ZsWwZh;CcpWP!J>b&M7yMmUd!{X&UJ3=?~x z5bXY_!Y#)u0+)_O)IW`?v3PW!;T@3l44~=R&&JA8DBZ(un)f_TGkJ36eE@BlU^{MT zl~U3_jO#|#?CEyMVs$hBkc1y?2Oiw}F32D#L2wV&i$$3zwWxGu41dF1dhToh@gr?| z5XNcQZpw(wU^}S!PUps!$PX_d72ydTb`@$K(_LpmrF3w920O@gnNG-f;Ia@Xu&Tx#Y<0#zk!J;HE|G)thz%Nfi#1^ zxR%-_Gq~zaeh&gJzrr?SHlwR4jd4bI{>)srWljB1Wdc!U0G8FDHUph+fV7?`SciKe zxxqM2MB9|J=2|3Cv<(DvU5jc()s2|&6_|+-0x97nX8EFa8mNVkezh2#mKGhW#v|}0 zZi=dG{I}NX-|D5A6-k#`nYC_3sQmA=Hv|%fPM*9Rk;sY!zB)@Bv@Fenqyb}$)(u)o z8dc=3+VVi1*>q=Ed0gL*8ct{swxtkec^?`Ig%J)*RY;pcSUhZ5kqCEv-!C1tvK-$v zt*gF7uYFB`nJ7M{$8)dOY2wCt>X$E!8`M6i{_nOE#{$KLup2S<%B`^Jnj0B0IozLH zmd_HPOlF-#&eI(DSQh+vMvt?-cq|?oYRb%ceYN&I;XX!XKwdUcT-F#t zAiNv?%$Bv7>Qb8edqZK|^|5p)2FIZanbX92h4=_Qz2m`o2C1pMRZR}BqW(MDMT=H{ z=Kqj&R&8-bUA8XV-63eO6z&A~;9j_UaCa#zxCIG83wL*yV8PuTg1bA1?ml0ii}O7D z2ke`@=UQ`&@s5=?E$lWfkLQdok~HDFUfRBE>J?}l)LG~S9!e$mLSI2Noi7lDtm!kB;<3oe0Gzvo%!r8#w<4CaJv z+402Fa_8~?TAPWAqy93c{dO0gY)2W=Rozhci2_+k6NJAKL^1nH#@}PzN(ob|z>Kf4 z(1!R_P$Z{gjo68O2>be-hx3#>&(of^k5b9s^g}z~$AIGCF@&DlIiT}|Sd>_U!GTHZ zDqto(=mt|nyV{F|cr{LB9Yy(rVG6An7INs;y&v$10_bl0gFf>$$LxnZ6eq`n1la2K z`7Vx;o*GY^l74jcbz-6l?y(L|`00(`_c8I@^aUbRYwmc!LqQ$ma3CtZ1c>WOuJ+T6 zC!1Tgxc|_c5j|g=dVS?m4P^=Zp_9aa*THkE%+*0zP1Ku9Lq=aRDsPP>S~r@>A*p95uhgm=U{M2HRwM+DBw-k2nK{jf17j&_ce zudt$B={Ns+urj_hw493 ze@|{ikG@Hr%l2YhcbyvhzDCQ);!#>FFXFAI@s|Z{o%HUw7|G(tZs`s!94-lr`Y4Qd zr4d%e=vPBcz)$Pp3)IrT+z-SLI1s#z+#neRC92Q?p1VjhK8uhdBv*mF&c*xTEW5_P zka4sn6*%>J9vfrW&K^R1Hlh}Nf460byJVgUrl2`>Z zi$2)n1(dSYXhWjL`R4iD%rvE;YtDaoeJeTRrOvDKRRlCc>Wq8>rgx>8 z!lE&Y!bXZFij+NzvX0brXU3X9dy(o0)j!{C3emkX*LLV+9qPc95q$E1d}qC=KX}Fq z{8-6AGd+i}AGO_IVbIP|Ty(FlH$6&*v_~#dOZjGCc4qYqa^&NNRZ2U`?X5jwfvH`P;wFzfcj+24M%Y9r|!o{Z!@Qi=BCGp@}@Q7jY9m#a(gA z&?HkT=qMZO9cx*D&FJJYK(z6SPil&uiB;hy>nnLUa8yb)NTjTEMcXTPVbOJ-O=pFY z#I%+q#bp=jK*gWEeXNLHJ$)Z#k3|&~{ZVN(`(rle%(oWofeL<1p70DewZgCLl5mZT9f~`~O`4kpDhALr9jG76e9q8m8q&{^DQ)DJ} z5)>|%UNO~B=Hfzi!-`dGFnJxAk^+8&p(2I2Zl-V|?pwosKxQHagFMah>E=k|0jO~! zG(SW6pnKM!OKGyd_w)jKvh^MQp8E=Yd+k`0`*1$)EnA4sJC28dSJRj78RM!IjO zz)g_Y`yP8@}YPtWe%j9uB<94%f>W`4!@LOhT% zkf4B@wA96)!2}$#7N1g}{^VV?Y-@LOu&xu7o#9X;#UmNEx4}sE)Y93md%authX5qM zwf$;aBW7bgcQfU~Ts9F{k1ClxcFQ(o+x{NBMQQr*v}kl<;06b2muup`QpgwavkIH# zCN;s_+>)s~u4r96K#8X1(*R8lz+L$!Zl%*zV1EBuw6qSYl?~J+pTxwtRK{voUB~Sd zq@Pj5(gFFt+}lkaef79ZC*Je{Ypm`}s?RzRDge9DE(({SFa* z)WJM!*<7jH)QuD`5++NEk`AV~krdFO8B<1wY3l5f??ZfOzu9SK;ZUh_)X_}r_^BW# zN}3#S{K-zxz;3Xh^nL?ah)&bwM5D6R-YZKQxB&x!k}EhfMRPTO6j>V{E?pK#hL@oW zHsj&)w)i)e2;#4x$|lIpV`8*78-wDl8_>WmX(hw{o^8; zfy-V7YAK%E`>6Yv+h!H|KIJvl-_Ge&LXS1fclRp~nc;^d?iM)GyN!)f5GP^STc2Po z=o?kw?6PFL80#*KE|*YKWbH=T4D`_E3W4;$CHha zWJEK7DWs-LI9Fu&sVI(AedRA3tly0qS0A3oH|Ze>cuq!E)I-1nMq&}ZkS_b)0#DP> zY0S}$EUmIrljOZyfn(F^7#OA@u~c;gi!TaACW5rRstSg^l45u|=THnr#Swwk@3|)T z1^!$PoK{t)hPt`pEogoNl9Ea^SmRYv1+Fx`TL>Y1$OHEuJaU>w0Hl;;I$SVN1#GePU@}6x`aFn;Rq8e4y6OqAGKD;0VEemZ}pBJ%5W_}xA^iW=1HO1 z4jKT$~E$Qc+4}?GM|&fjk1BaH#DEM;Kf@BRx-u$-dLNlK>Pi(lie7 zJA=cN`W(+Wu2lBDyFL-GFQEvE@pbYgB8>7KtZ{>2TL-^rh~o=p56WjUP9)5URwU(q zkS-#MvDc^g#bl3)Z7mkcM8NVp6ek|&p9g;vAbhYC`YWPF0?eK+{2X|z!mlgWd~i+Z zkVIKacu=asRHsW5FZgmJ%JPN?&Ha4PjmwK|F~b2hNwb)ws67~t_i3pW`DDq?eeu!Z zR}i>D_{B->yzIlvIt6VF$aUEVmQNcw`q47ggT9lNhIu{5H&XU7m=l~|E1M_Qj$iAn+b(FcT9M@7trz!6F48~M zNB+Ug8k_I*O?RWsFTr!Je{)w3v4+MQF!{UA=`we&&lGKsm|c7NkUBh(A}-`{d|*h- zZoE7po$jkSbPYJa(X0@`I2O9a(;&a6MDZo}#Y&f9S#Y^+TRJ8R$oh5JBokIV*enmR zSwp$Tqxb1KNX^cs|ADe;_}-bo$sf5iA~)$aLZAeP<_JHA|Oy4=|%Km6!v>rc*cXXIY^2Yd6JhdmScytmTAcf z7cunE=sZ^sRF|-O%!PmDvJRp;2e*T)NrzSyrL6h554*z$mw#3%42|DQ+?C#&H4Bf- zy;l8n68fc2?f21^vr_r^`-2nq|3B}rD-9<9gXSI!TWycJ9@vTlmxVjeA5~m;(_mgH zSUaAu%BZ2hl|vJQ`yt2U`tVErd^PUU0?gxW_^Tsa(j_hLBQTKaGXQ*nIZcz+@Um9T2@8LeYnHwKD8aMzCaMrSO zZ2Z}-y05g|j2k_t%;7WrXnfIhWfZE0Zg9_nc-8c!{E$zB?6s_fU1=NoR>M&Y2x-`g ztXZyWkR6aA)4!v*bb#`)%*;q0SNnGSq*;}x%die>!A7Uq_#cq}c_EO=s3e{lGMrlu;2JY?-|FK!zZ}mP){?~xq z2GZ_}N5$j}V|tASv1;d>hcn~aftezB83K!)hTPA_h|A{_=Kuulm=N5zK>e; zZf-(l-Sd&O8I9gbX7a`9;s5NrZ>Wqq4_84o&%Xc}h6sIiEoKsu!kLC11`W$HY(G{$ zfNK>JLwv|Rp(j^T`!?%!I!qcAyzhdZG}AA=5gPt$igWSkw>02aKU7=Ud+4RsQ)0iF zLI;{=sVHk=UcI&{U&!@t?Kvlv!428)562gEx*<=EVMRV=pM}Bu?z;-3>wh79uzeN1 zYhP^w_+G7jlR7(R(M{>d_hMmLzhP8sN}Xy~Wz{{8RXz6G2{bQsh$c&CG+J1ZRxSRd zl!e{%v%hH~TuJ*7BL$F)>F?X3XK&O2;G)Q_seOmg`$T#_3nplw%Jbb?Kqp{IS&&g= zZ{ROHc#vFb)I$nk5z7;akSwaxr7q_Qd+UxINp`y7%lVB#Mp{bjw1oVzNa?H)K{`3w zsReyO-XS6)Ok0)gily?rM-6JuXB1$Xf!q>nN<|(c;=U5%h=For&?!MQYl%&CYvKdP zf@M8EV}YW-NxyEA_py9*%7vaJfjWK#RJRKM}f>RMW#ajxDI^p5g( zPONb{m>V5ZH)H432!yQ+vGI51JJ{m~2ReNhYg^id#)CGzKN)MO$iv;g4uq#C$ zj;WSKwVr*S4nr9>VOEWe`K;ZyMQ@q;^_XxAaG zdJ@U~48-+GTE;=xt}v>qVJ_Y%QT1#)7seuk>H=ly0Ht44%GEJ3w5SK{(kY!zN2Uo$ zpHpGX_=BuNcVFnlj&6Un{8-kSf*+IGkgp?TT8m|%iPS-7km4Qw=dJ_rB;rrweb51a)CZvBO3Iy#@-6YsxJ##97m z$#R+aBBqGI4>9%PpL6ED?~WtTQQ{DBwub##SvVii$@_C&=LVRZJ<_al%Ht8yfsUPM zxv!xE=TDRjPc57uxh*u#`&`w>iQ*BV)s2gr?<7$NG^Sx1+(lnA42<2Ai%|2Danr{k z`C5b|9tKGaIG4Tn85l(X07~u{DMnk2i~h+qtE`0t+RX0K1+Y)edB-e**Z{^J8wF-mwuuG4EHtY z(d>lxb6#p1V|dW{s&z!A6YMp{Sh$$u4va%We`?Q&KP?m!8C49U^lD#>bYZjkWd%|! zzEN+@ZJd{d>-rbJ*CW+ujA6J|38xzZW-Q@2*?NChKk5*iUDHj6= z`#lidPAI{zJ@^?7w4F-`M?=!zpgL#E`3O_b5xH20>5IQhq`C$wo=-qj)svUF%dX3? zdh<)qi%_#%G*2pXHQ4uz6+0=ZyA0OAsP~0^ZR?9r^dDRpkhw6Kn_e_|q|O>z=>f(8 zt(7OebR5dVB`T~`3`sLrvcwuMFWubfV|#+r;96CNMD;VD&9+J9SnGFxHi#{u*B`=j zlaaH)Tn8DheqIG!ZW0>kQ31m9nsZ0@nj@?&e*{ z+U!<&P+o6SMa8D-lr^F}riV2Y@{;{)qkK{Fi?UT}JYkRSCq)d_*MA0y%!Ng`w`!~8 zliTfaR%J)}5xnM+yL2x-w5seH9O1=5Od;_q_A2C^K>= z9g6&jN&N~Ga6|9%Nl{`UjO(iCRpUbToHx_sTg;=I%PW?l2&NE%&G+ej+aLHW1gehE z<>Cwiaf^xwsQ-&xKwgT85m#`5&qTvAvVwJXyP*t9(sPnx+2a(dB&scgr| zN9eskY<~!I5x&0 z23kLt`58pyps&go36B!SpFnNt2<}}X5o`cdR zm6n0+th3$SEfl?sq>W0TBkYg+#PQHCR@*Q8A%h$1Mm3whos_$FeHZE~!Ih@w6nzmj zuLbb?zT?F!#pg%b3sOxBJ1+41k%x2PkCNS62&+HY4Wt+S%_U<|8GY(p{j|HQXnmiy z!2zdTPvqNG8}Ebx_wO(JZ2rZI?UTTw`?qVhozKAUtk`X=z~gkFAVkWyU7-#ZDH)YX~RwSmEQ_(cbq!X>vc3>rP(gr!4?#J_V(+ z2+rHE-%g96+3O>SwlL7+d=`Z5OVstqc`W=#oW3lY^6o zD%`^uf`Z~G&nmPw!B>|m4Q<#y4=)XX8o6AokWsj}DO#rKXHq_9+ zLI2!6sZYjB`OvM%sk~EG@egv99nvE4Ju0eFR>0;Xh*8BRPv2ES9dqGbTt~Qo#E3jy z+Z2d(_T?)VR;)TlpeVe2ogex8?g4I98a_Rx06Y^aD-FMkQs+5qbi9TfC&Es`qg+iO z?)G7N#}P<5Kqwy+rp)-oZ2d3Us!9d2F#^~;FbVl*B+6xzMbQrCttCkoCs@cU=IIE2 zWDU&jOj4HtCjey(Bt49`DGQQA?pW4tyH%;Xtbrs>ps@Z!-+?1G%W{VM36Ib9{VpsR z1c9Ty7*M!C!+dVirvC~}>DYwF(cBT)#D?=b99WDn83hE+ zbPw@}2c!G^{DJDPCf!a33mnqlnKv zSCF50Idb>ZN$~m)6P%&90}cbLUv*g5k0(;ni(O($e);5bW{&>;JSiEfAKFaFUX$a* zoSm&3z?H+Gw5P3ndcS!cO}EeafKnJA(}k$@ca|q_+r6wHW6lB-O3r}e2IpE`Cc*s;7;b#hAj`iP&YcBz z)TEUQl_emsYn~WP8G`MfS!*|P=!U-EjI4C3co(S3krtNUAbQ?L1Np00s<-D21=vs8?Q4)g0rWpg#Gt|7nCAVSadXA06@w}hVHkx^ z5`kE6w`1HmBWKMA5Ntp>e)!F1|S(($d)EwBrtvQ&QxlO@Y&hUJmKJK%wj zLF-+fPmtCzoqvT3Phnk|8#fG*l{$}tHF9jtYcS?bO&|2a-S{Ycj`}DO;+vOj3y?+t zZx{;Yu>*ReT_>L_MO!vLGgu0csw?>M(qHA%*t+yz(9?6A=)D?P&&oDeQD$h~#8`jw zrcXnJEBp?_t2&kmtDZ-B>z1Vx?SL@9zvaRY@Kds9_kXVQXjZ^^J0m|=Nz{0LG(y@U z(gIS(Z@y|aNq5OF`W9<^>Nc-yk-PPBRYch@N4k3!e~+dkSl|vSLXyT>M71mTO-ggM z+i3aE#@X&gIi3t34ZacUdc-W$mVD>IqzGeMRL3A_@7WY;z z2#B(iKY|1?&M-)ML)-iJ7I%4u{=&gjoDSLFTQLxwqYeTWm8KU<^Zo{4fkIUy?I7Dd z>^HxCLffT-t)Ky?aF?TF;&c7|Xw3tq=Xs*Z05@n1Bs{+UL{9!&^TI)= z3z9r9B(L_Vuph-(>!rMF*xJG0uExsX4Ky*nc!mt|OgQ!4LIlLtgb9TbjvzKs`Q zNU4R>jUCwBM(R>%rN91)WkNf;eO3^eSWc7L5)cuTQd;DdSe?RAt%qJLwV{f{XB~qb z)>$i%eBB`Vlm>-_RZFDvFMOP1bw7PiGIVRN1!14wLRh2cS#a0Bs(Q^&`M4Z9q{PHi z*dwP2ge|XSoU>&Ny^uxks7nbfKyj~n4=czl zvZGgnB_Hp`Wqp5u^F%`YLh;E0ZBej0mBB1gesUCHsxHbIx0f@ov$g-lJL)>U7&k?! zK1~CrI}v`B6R|g++v*Tvh4t?VDB&H9O})!EFeEyI-gZNWg5{j5&g(r44Tu}y8l>yrnAIC3h19qhWRiEE2uWm`6gml zAus5)%39AlX2Fy71V*Bsn*$#>GXV6`v*~?{|2rH(Pb>VL2AV$HLe^yd$$lu+7hv!- zU!6@FY7dMr6gxN>ObU^yNQ2&W4}RE!Wh6?H<0nW#MaAM`Ev-`Xks@-#z_jStJCsxp ze?rVKWI(1A%za#cb|K9wMTQ{`HEN-pg~E(YbNsmN!@an)Swa`;W|Dgtmb?;Az%>bf z&6OH({?d3*6+`p)lM`3R;_KzgWtdfJ)-EcpXZ#ws1?a8@zl#^uxNkb0@8f|?dIVGuC)5uAzc8& zBD{K)!dHLW^>vZ;o6;o1=ffFMo_E^bedW_FO7ZacEW#1H?nACXw6B}##%M`y!9UM} z;IM)&Kema3L@+rZzD)A+aHuuq!Z1nWpOs*{IbtMKiO`z`Se)ZT|1-;&3gmAfuRmh> zj&e1yF}!-(Jnp^oUGpzXA=<>62Ek|`3Xe>f3dBQ^u{HoP5oOD8n^;5tQ}%eFwf}q= zWoL;Uhz3eVMRI)zsQ3$)R$&A}l83NiMslBqNC-dVALU)AlI;^#=`CrCDofzx5y(d2 z078sHW@Y8-cYB2vIX3bwV6W&|`S)YJ%qi2}=p07v8oDXUj#Y=K4cVt+7F*6n(%d<) zN3X|a{sW-v#>1)Ds8NV$E^LKOOC+$ukn!a%K-X=5+dC!bp}sYaYghm1pNDM!!^r0& zZmJFXkn}o=4*npCU@A86Kv=L?*pfFz`Kmrts>&VAxI-@O-{|+{m&jmb+1T^e)VZ7G zvYq)sqK6w{z(5$>;TId#o`>_EpIEN765=KCY`q;LEJ0tT7Qk9ORaPtTx^6@!O3G-f z6dk4Pr-;9oXMg*>e6Wr{&P0N#c1W1#@5rH}y5^)Xn{Simlh$7A{O5Z6myW6lb)M5+ zD9SZWhoQ)hb3M%F6pVKIqQ@{u+(oe8b}%K1`IR}b*wKCt;qa8*Q=F^Kq!-JS-Rime zMbOEeDdLSpp?Q{s-_w;zGfW7be;%(g4XY;EmSQ-XJy2Zl{p2dZ*g*NY_b)vre!I%w zifI|DDDAekM}!<-V_Sliu&P+&$Gd6uUFO^vP3)%e1J zg-UqL@Hz-6R+c>%XRCW5CQ0N<%`o|({b8o>-P-Y4$XDD(o#vl92aj5vHQD^f=ndg) zH$ZdJo_}K^bA1qf9Ll3?0J#y{?t;kTy`y-~hQ+|s8|~f=|7XAU%)5t7rS)yP7v%kG zrU498A%>r@(Cw=k7g4`BQo>?r_x9e}i|<-ghn{1=CBiIUKntI!jHE>nC*Y@>Y1WyU>Tl0!MT6kEaMEv8k+mO9{V83J_~YT%IWDg2T`Qjy7;>D5FD9KE^HJH zcYc1)`|2CDWl(nv&f;-MGAzPl4!$G$R4*1Vks$Ix`n1K_#M>wxE;BDn@T}vM>#)`* zMyB9A5?lVQuWa&fHjJ#VC7#@pLeN}I$bE%*$6CrB-=~w!#s7u)s%71g2lwmJwY8q5 z>od7rir!*t_<-5&M9tHW1Ra_=iA9#AFdHgmK=Bn1LqX-Tt%jPt3_Oa&)Ba>Uw4?b= zw~@vaFIB52DJ!+IY;hZwIe{+rzSsLhsx9k^=<`oPv;ijcO9TBlVCl0_7i#Sa?ReiG z>s$jnJ)1TiBzoPEezu%On?GTt&V&v88XszJI~s(U|61Jl4tt_}O_}TGvRGIotyDmLu5Dem(O97{g2=ba$3z?;0zj zKd4{*br(tj5mWiBk)$4i*)58&kA4xLqf^2_Q7P?<{GW7I#p*Z)4VGj#k9gA_e;Qyz zz@D{&fn#(rVTKYLEc}+b2w@9S+Lv7Y}3ypYlg#w%I;V*BgHbdstUhYiD)R~ zP=*C%3MQnn$jou^Tt3zF0uCBxi`7E%sOE3lqTczD#h*TnXyc%bWc64Mv|;dQId`9T zz7aophMDtOTsC-J{`8 zQY+iX5BH%f$JaAnbNp37aYm5wt~zk&-);Hc35xoJucskOjhls*Low4JZ0o{fn zOn?FX+#6h&xuCdtkmxC0hdVP~aqMrB|cJz?N%Ny!AAd&RZRuU_75Palja@hgKx8G48Wfm$+Ze;FWc7J6a|> zl`^ulWSNCZWpR2lcE@qL2O9Rb0@hvRKv1v1&}C$f_=;wrW(#S|XVRzVy*o)!;v>p) zTs)P=RVxfGOsYezQQcG12D76%5ZamAF&#l^nGEH+#Io>5aK*k1J`CI{R~&(rZDI5U zVvgsjd;4wvO#!de%}Bsq8Q_GW6G}9Mcj;6E?DTK6#W|9~Tl=EfmniBckdSgLdzhwj zZ>q*%zyNIfXTp1%zkMTH5$j2rFE5SIGqRDLKxT2FR<$>mH0$Ay80kNRck9miz|aIp zn~1u+Y`bb+Y5Y36RI#>dQ8mRQR^)%+DT0GP12iCThDpdFO&KSL2bUwkAaAL%R-w5o z3|we`eQ7=fnHfxiYV0a2pdf+OCq{gvAzPw3*MHRDA~dRscxJb!t)cX)J^Hx#ih13j znG){X8;$}hiofKZV2@{0kHRk;L^t+%B-sQ8_B=TLZ{`*9!ZR!rk*k#Z?c z(ikqr#eG}#f{F(|f)r%N2Emo_oFWYwO%xf0pF^~{C4&gBL7mrW0yh#N$mxfzdvDvd zihEjAHm?FCK(TxpqIPfQ@`cZHT8CK_;dhy!0xq%-pv6b0`Z@BpTKApJcN;Xn>Rm|* z9B#YUq?6|I-YU0AAr@VwS!;_%)S$7BDXr4!wW|*$ya#{(7u3g5PpM0vB6xg<ZL_QM0p zYkAXOc=PlOmR7Viz4`>FS3+7T=<*nxeX;>w$B>Ro)1KFDa>8!ah@BBgGxS3i!Mb48 z68lNGFR!S-R;U`d%5h9&3|oJM0m7-dENggn&Jp zcE3eaK7@>Q*bqsWaMxMXC)dH&933WuW60v;?Ae#$C=D+ULwr<>=&c$Gvblu@+s~g& z&Xi@wfktXL4U&oTb&+uEXv+qZ?7PRPu0)W)FYVib@Y*Pen>RqC7Mj)fe$;iA#b}hm zYcQX>??WBZ4#Iz#Q}5@D_Ghu7$4onb3pX#3SRO?CpDvru0>V9tNY@2VF%^AlRE)3r zJ_Ht-f9bCaF~;73LB)}K|QqINS}YSvMxZlM3+>~nXz zix-Hd)!KZtrO<>#QI+M$D7YH6M0&x7dw{81kSbSIuN-PWJE1c+Ib3qp>{Vlf((Ow?!lSiS*9_)cu(MvkLg%pRjMn%# z?neA-cpyNUy<;_@k=UaV)oMui=o_;pKZrlLk}pRUX<36rLycsLdG6G3CKUL7w3?x8 zuPjOQH;Y=3WMmLYyMG@SY})dlYGSVbm%QrM;F>1N5jgQmgp}aSD#_X*3lR$sTV<%= z-ZMv}2nZVpf2iNQi+6f+WflE4mq{P&us8KYe~viAfHvRgPzL{Rkcho6OM>;8KOzKJ z4jLEDc^&8S&;dI~f8NWC_yLmpY4Muz8K3haH|1v1EIdy--(j7}i2e`QQGMOD?B_27 zq|@Mm_8GX24L?1e1cf|y-cbTR2k6VMgFJ9jpi3 zcWJV^G3(wKvef5)j0JQ=Dbof94Ra(PFF*9zv@<6PvXodg9Q7k2(ajYWcyZ%*Up@O+ z7|qwD0zZ`0)q+T$fJC*eY85+)9gpYz{(*FUT(1Hy%y#Wyo?K>H8!J~ZS<#a0D=KL* zIEw=x^ccVXsc7xcnAN0?nvxMfa%K1FO>XB+M&|9M#x8}uh^MHVPStx3wC=xvMC|O` z6VA{Dz5InH^oy(mO`=u&`@7UCF1I|$@ll9kZ2;fzk-`|uZ;f=)Ft_<= zZuK|m(hdv@W!@n9deMf&@-DKkO@Iem@-}>_Hn0`O>I#p!0pkX{M<9}lYrq1#t4m6- z(*fSMp8@6<6LN<@RvhM~`KY5}|Jc^r=-`$xQ0hs8!Vy#`H(doL{>d&n?>ihfKO> zkq(BB;AB?iJ^W#Y!?Cvmb~Mu!s6e)v*Y~oCN+f^`(<}{&o zISkE50Rbp`Pc%)k&E-N(%hWADUmoGU!*@a(d)@hAc#g&Pozrxr#{Y;W1o{daBxZ%w zSq?9x>y$&%@Z~`i!Zf~{OcID6hiUr3aI1a&=hVcK-lu!@_L7Y@%fk-h_1TT@AitXD zgL_N8VN*%(j8k6gCD2bAEXJHE&?w7uk<{kPPu=)6Xo;wuG-X2EAD&Kv{-;o<4_pb$ z`GKO0!;gk#ikcwvA0>ecy9lB?XH^vj^XqHJfEG%U3?bVWcTJtU%UMW+sTEW@!fLN~ z1u&~G^SPz6**k#aP~3TZ4_N(O8m+hg!M)SNEkQ8sXBCkBMDGaRt{{ce@t7_v7&)tg zd_6LFC8>fXh)FPIS>o@NV)XDNHq|=U2oO_7rN1#1L~kd$1HZs_ziqGr!v8RejV2 z>tZzF8ZUi;nTE?<=DMItXBWxe&tRuf2k-uQ718KMH}|n zP}N+@jiJ@NNxdW?Q%v#y}Z}x zB7!UG$Qh$1Ms=LDJu#9UK_gR-%!0;Ntx-l$7r_wG!}vkINQXzr>C!Ep*5?hU5TD(F zNgJv;;%C7#-ntt-B*cu3-U>`hCjJ1lmy|3UQq=6t33c1b>ql(NO^!4I5I0x%FWlJw zWJ+HtdTnDG`P%rAP3|-1!PQgOzN&;_*LlUvVnf-LKj~N@(QlBHoEDAQOw7vyUo8bR zZL{zJpSSylp26*wyXnXV0;vmZ$!9TdtcOqPE=s8_OvdRj3u6zbcvxeyjs=ucjMMYW zc%6p1ai7lr-z1e=xt7rniU4D6^((PoF>l8iwD&xOeV+bIK}|befN8sN!N}wHnZqCR zB%lN;gEhV>I<-Oe%z6v+7W`2GEZh1sNEDvo2i=CJDvJ6xvh2cE>=6xfgeZ$x@Xily zzuAp<4!k5JUyUK(R6set79f*+-GpNd9QS1h0Qk-7Pk~Aw+CtYVk*;eU_TW90dSYr$Zx;2;w| zvRNv4d(LM7S^b9y$q+ARUp>;lHD>=A2#V}MJ0)8nkuzSqxS|^FZ_fiw0v(N;{N+=x zyseVqL3Icj!6URM`xmS2=R9P4-U+EtkU2_Kp)dQTP>Zz1n=`SXF=3Qm)tZys%Zp_9 z_%niLrN%f9Kw<7_kLAY0XL{e%{b}P#xkis~a0hAD?rq=e70gja%jei2)b^hi1f1*Q zBljzh-t}-%%LBDZ3B5*+5>Aj0-|P`N32ksO%YO<8BC)Ts3^-VF+SH5ewb>or%h^GF z#cQ*qq9~TFlc*XlGonaeZqiThx1)P8m#5j|rfZ@H`-@mHViUh113-Ijy?VyJ3n zj?<*-h5-IP57C0HUlF4QU@;MWlf)62IS#o|$0dTbDrikgah^eLXaj*5N~Seg0)5eJHdJe@pdxW~K+qY4xKUrv`qOp6#cLCRg$7 zRVS!JoLi1Xf5fsheBe%GE1XUfwrZ9=f6~6-W0aO)(bh}Y?nG(^Zza;g4s%AXEDu-{>1|A?XY6=D=m3=ek z_|oN&2)0g?;S%^X@P4g}AWE0PYi54r>peOzbCWbizT*vW=ov8H+8L(p_?G1OqB4;E zjw1YLM__xc>s>IPZq2991!}CdaBfJ%86vT(DESvJ^^hIQ$8KZEyb1!T;eT?yCE3S#o{r&I0QbEtF^Y7$70r)n$iJ7568-!SO+BT;hO4mF~i-+|ber)V| zpx@Bi%DL2$V#OlRA(0DFjFgn>KNDnKl_+w&Kfsho)WZ1K7%84Puox6_#hzdOcEV}> z+Fmvac3M6h?cyIh)8N>T4p+f2jSg@5NI(BsV`~v#=6gPAnAdX|h$g}^jjoD7p3|R! z!zDiG$~%G&Q7c1q5_^v38M$F00Ag!ZoX#(R(%=K{E{}GWJX@kPfqlSKjM{gD%;8gh zhG-wSh*_a|pzB$SMj9_i{HWB3upA$^7`smcO>p7ID3F#d^(6Uxu?y{7qr&ALOd|Xu zB%EE^u9w`P8-N@9rHzjt@>^r7OmP0ZFripXB*9 zwY^3PK!>X~8Ose3D2*V`%FDbuU*rf;A^Um%lXg`yT4-oobl-suy6_NS`O^ zKc7g)pL&xQ%BK0slBbZrLy28yG(M^w_HZNdwl59v^*y=7)Upi+9s>bjM|gzkw>ry` zr~Y4a9EA>z0mb9G>qB2YQk_PZkfGeOkCtXF!HqXPl-}HAH*PxQuJzTrSFnqcAD@5+C%mfsWZs_UWv5Y@LQQ0`*~Z784DR(qt+L>0ouaiF!7P$?`k> zOLa^|xL&A3YD@LJWrDJ!7ESJnGZ?=oj`fc3W_^heRH&pjm$cZ8Chwc$6ft2X|8v#fA z7`-w@kzVFpW*KQ(O5}GphiO2EsE0D8jA5O#gJ~620HhX=dMI>i&E~dc;}?fS;Ac%w zjXv>~Uv&-Kb^x#rNGGXw(~1`<S<}5mq(zqNPI60F4%S%Ft$ZxDzh6g+R z$$GF2CLXAtkEF?S_`rZ%<*B&(7H=UbO579yV$&;5u|}^-6l1>8Jau{00lUwv$nDk!deJdb%EjN-Api;*Y!E_1|7d?Odctp7?{VSDXoTHiE$d;{4es?mQnoUQ*Sm0Ts98kq)I(!}tO`$A zl?Vf5_9(Lg`$T_6aIOeJlNFy4!`w#!A&D*Uuwt%}{Z87|k>s>!7&+Z9=W!1;NqJ_kG7Wm_&!Fe)ZSQimAEl`>YW(XqtNK2LMea z>BIAp6j2hXv*Or5PgG=KTJ{kUFgkqL_~A)=_!2BWk{5)J+^hO{7IIl&bj_aArl3GS z2_4KX)u43((_2E30rt#37Bq0TSZYRLs`+lB$4pNv>a{t-sMXjpUY8kZ*NQHcDi~38 zu{&L|nX1Z9Y`cCsP0{@@Wmcb^1JCq4;Yxw!>eF-KExO85`WA2mb;E_Fs?oO6z+@Kj z#G&h4c~!dbSKWpNdyfvhJo&|}i!XnX@0(&MmQqqAEhts9-3zLq9C);gbQ0u95Bzap zitDa~m@+yIt2Fl;D_y)$`?VVC|1fpVZwrzXzH*>08J4~AF zsmZpD$@bfO9MAI}?=Sa%aNXB=t#hsQ`F#sL1t7tE=>P;MZKqA5%mSEIWm78c-Y)Dx z%w)-7*Fc%3=FO#O?wmDQYU1wB?Z<#;`={sNPiYVDh%5PIC$xw!&4^ixQ0wGG$u#{> zLIKxLn%!M{z+QF4g;&sY8&nR!NIphZB3N=_LJFqhNLWRc;C9Zd@GIu^K?@w~wp&7_-WVp(+wQ z)yIFVf?coeM>B0Mc=DC-lojgB1lXxE=)?GA-}yRhWt?-c2RkI6vpDw8Ge)&M$ys8< z&T2oKvnFX*H@Eb~RA_@^WsREdvRiB$n7MPCJ=fctTZ9$I@H7oN}OxJC>j;P;}}R&X@jz>W_ffb^P()%Lb4W>bTki zB|c|_%aFYOf!+4eyuirFb@4Y@SqT?bGD4ge-9?+m3paG=nJNpxS@AeMzrQZWYi0&} zx8C>Sp|^p(D&3GeqS;Z^Cign=cn0nx;}ow17tBGu8EA=KH-cPDU)txzGXftr#_FTO~(!TC57%*N43?Gk{~47G9FqU7lxQFVun#e z@VhKER^`WGiTU2(AH11ynxBB14ktk>3AS|ST(EB3+>utIk2!@U6sum2)&i_5kmWor zf)0|D1j)Zf(CgB!8#1cu-=sykR!8wuf0OX;H~;(m-NP#B@NQ+%kR8{>PH~Y;9}P{8 z9G7W>Xc%rJqEzG?njoy^=h2$L>7qRDv&GLzUci|my^zG$1)I@U1oDrx;*g>g!(>mb zddHK4&*_y1l%p-sh_Urf!zEpq?X~-v7AP#BiB$yRsL1nRXQ#B}1L3P^w+`v9YhD=3 zZVQ6RI`T^aXf!rz;7|(4X-g}FK;;0aF2r8p->sNoRX6tKT!~ssAv^lR4nhb~XAu`) z3=0t~%YV%LS&jBC5n`)$zsMgWo@YHd$|hg!z2Q`4T%l5FH1Z#btma{?_~n)JScxP~ z)P-k>Qpb)0dT6^2clJtYK~xsYAbOooKbg+L1qqKiihp>9|M0qoC3{bNmr^Z>lm&+5 z^98l&m9g^7GGFp^9x=zfj|yC#lzKgebiH6ki)n>Ht^OP$ABOA!50P$d|FJV-7~f> zRz~zp9_TDKuQC(WcJ@5?xa>9%!xY61O}|PCi}hofFhKq777nwwR$vtKGjwCL zl$@iNim5T^oePl@+JF3ziee*S*9$S{L(zDeGEhkkQ#5pA%=UF@@l<4&6Qt-R|+PK`}ML6_U^QWv$Td^|==9@=n zC~U94jS*f~?w`K-l-D!PDGCnXyE5$)usp#{PqW$kDZtp+9%&9$f~*_FYz}23!so&D^wa6z@RXf**g5>HNfp=yWD2hjs#ChN+LiFBpG zQKU^9P&DD@S}|R|6N-4CKx}~!}EdoKl0Mgjp{>t z5KM6*lXT{>tIwhcT?y~xyNIt#7WcD$39z0j1O^M*U`8o{GbI|rm|Hi$@Q*f2i+h1L zW62@oX@3Ya6HM>v%Jw{zv$Ri>?_UzpMR(iSpIU{?w#UGa92lmIud=`&R4r2J;)Q31 z>@r1YBWty^x@DT#fkNpE?n&)3zt_Zrt0^syk|>#G##-W*F`GZ_xrB#p3kJ9?r_|vB+{2e-|cGm8+j+prD~^ zMyp$@#xhpNBjwH3fSnFJQxb#+39019vTwU^m(_vU2$!}zD_FTN0g-85&KE3dsu6YX ztL|5hgB^T&EEvgL`z1?9NbHcB64`D>I>J@k*cg*g|0x=U|Dw5?{WDn}O#_l1Vw&^o zbDGMTQ(@GwLUvL3F$EB^uBXsy3Yi{U&Jm17!|o-Kh@(nMusghsk&?dZO=ZR;u*Fhh zz7KF@73P~6`3m!GkwV`NKP+#~%4C8kwEN~pdGpL}8{>CKuYy z(I5gAPc1~dBlN}Lj+EZ!73r?3O}Sjy?5#6^c1S#4UmfNnDo~0|)3#EyW*^p6=Xpfg zyNh7bnd6(H5%8`9yfR=e2Si7oNt@l^^@U*_MAU{$#LxyuodGN`z+#Hw*`oU`TY+04 z^L0ft(-Zm9DJYnBz;d5i`(1|cpU7UDO_F6*j(2Sj&1jP?u664kPt9o(@0#^?-3)Z` z+E$<(PgXIF1>0zl|7_e@Q~*xR*eP+7k8dXX?5k~tQ>(+xbv>x&$)AiiS78`Y@KXO1 zfrr0ijdo@rFM0DDUQ?ivT944vPwiL03sc2Ro>!}rZgZ3xeY%+ZR#_-Wy%`Q#& zY)X~lKJ^(;#)ebItiK?u@j;$&&xDlln(l0xc1wAoCLHub5y0+pwEFKE=@t?DRgWv^ zx=xsh8*u%y+f$T-rs>F1xplD%gA4muKbT1$fL=O^OiLvB3CbvrJFT`Xtg0_e%q@}w zJmTRkn$kH|k#ddegU1ZO+L;9$Ca@{TjqW~MVMUgKy}fQ`E%pt<$r*%w#vIzqLHsA{ zILW8lu70EXk+reLq9$6&|8`m`ciX|xZO~!Dd)M{5Dr~1gDXk60Ty*b-q|lkQ)$)o* z6^iqF$ZQpUc^@)I-Or=+qQXl{!t!4g5xB(enCbJxyd!B_1xl_46LGqfgBH<~o^Xuc zE1`1_iad%1^5hsGY=OiAcZ7s6(kxRYl(6(Tin#KD9}(#Sv_|z(@kxRekQoK80e|9< zJ76-I4&skcC@v5Nn0m4tyAk6Be#V^CJM_rN)p-L2zXzEIiiJqoo;_Mll>}zO_}pCj zI~ZgC3wlNk@K=kQIjWmi;Ka;C3Y>f;3OPzJ#ql(`9r0Z&K{yhsr>#hAQE!(~R68{Q z{RN#WJKIZNIG|X5h30AIw9m$#%w_ngBVGyKJhb-XMXep=OHW;w;x0(MJ}x@avDkTEqXT5YInn;^VM&|35Rbqoa~lRY}Uj5U)XA$VImnJTX4KcI4Qf zJ!4jf2BUSmao!DFm;GA6P`QcTG&2Ow1a3zm7_l}l*qHB}9n2q@dg2Oc9NX^`SuRz} z?umjA|2oymID3`Tn+9}p{BfFeXiXS$a00*S5yL0D_Pa=8d}BBhuOTrpjyj__92wFU z50seVpEz9VR5>u7U7-H8_VFz`^aKor58ld+@i_t_Oo1Ev9O0|MW~Td))uYvb>q8V| z%E(G@M524k;ebA%<7*-l|c>0?SZ~QCfy)Fj{-pP1(&M&^W`vKO_(xq4$IBwmi5& z!|&AF5B-ZKJ#(jEN_-`Kw07-jyQr1P9QPVA3x~X9Ul!M7UoD3%T=yK7k?g$pE1NeO zPRcLDvHW^op@l|(A1Q3+Cu$+l^f?!=N!QQ>n&{9S>fVKa%RT#sadq49Bf^P9TDeXS zv1bAD`AQ|E30xVNJP&^Avs5oi|7N<5X2sv#S$+!spXdOihMtELYGYB4#T6z-l-e+n z!LP(PawDmH%~p)O^!Dw=h=Afetnrf*tYENIeEYB&&yaMEiT^tuJd(wE&{ zr0@z5zX0)ohy#Tm5bqmtqz8`-5al(gVUS{Vd*wZlQA@o~3XZFX-Yv&3@B*yBkzcWD zs~=X!?4su!ojK@keQ%ahDJ4zmZDM~+U&)NPTF7j#&HQ9|AYrUZ{o&~u?IaRdVIX#N zxqo}7lXwWZYQN-a@A(h6@Exl2!Hr2qWcRkX`%)a2s5`E933c z(!*tMmV0s6C8wRHQOF@K72WHS_0*C`m7N-dg9I|n90i@uqW+ic(g9o=F+o_68hhw<8mt&oiD1oq81iHf;0UJ6}W@)fv6y# z>2Q>Yfwtxw2WShRx(UKUPMpiFGps(P1QZ1!%rsx^SW>-1Gh!N?v`K_Cqqku;3gQ~? zu|13=e-(VjRu3O<9k3_) zU*~;Z!3tzrsspcsn-%bomvlBjO~bU%DUitru||Vs_?ep)z5ud5qU8K?Am!J(2zIGi zk5azI8E_tOCse*UKuGT!GO0C$w)EH@vB=jvHFWg&p!6q=TN%Evr(;nTNJUA{ZA8({ zVoNLT?ljf{?3uHU&17}Waq;wX^202P&?DYHP9tgW!@xS`KWGq*GSZI1JEb;z`zQrHD z700Zr=aZir>^Wd}7XH1|i#YQZQ0C@M?cP=_-@&@37VU|0Je% zQ};-9Pg$KMneZt{o+7*Ueh#h&$M;t2 zc;~YqRFt0`pk+u}#PU2fGYM8Pa$9=nQetMO`-644M45CDwZvAhrq%9sxv(N5wWFIvo}AmhlQ} z5*ZL~XJ0LG*p|v(ORHyBrkjtT?O5JV$(Xi*biArbwHBt1=H3 zeFaa7>wT>S4c&?2CJ_B?-Vau|aaBsz;5#gb4nTDI0NTaH_08|0_nwagJLec_Yw7Ul1q$bPjB^`{T#$5sp3E3lpf%_2NQhpeA8a^*~q*aPNzsi(kcn8wRMp z3g7&1^_Uj-$r(b~2W{m6*@^B5^g;wdE~>l`=Pp=e461iw>HWh#g4sF-#e9bGmZ4Pi z``uE=9dc0Xup34S>sN<#x^6uk`9+&XYt&MNkM2xE0P+$w)jvVUF;|KA3x|^Mf_=T!{2 zOYa@=Z)rlXdP@-Rs0*-#Op?D8BJcmF5XA>Yrm@1i7OKI1Ne@dC_1gc4F=eb3rZ>Rk z=kT{!TlfYCdu2$g?GowZw9MRg#yDoX)VT2WDYXy0wX^n@JlQ2OMAgzpA^YaMut%tk zrjPfqiFY6-I?#XLMXh3U#HWbBN)hsW1r!L>@NwVQ|EA|cg8%)|TtsoGLqB!FM6RO+ zI+BDja5u6R)V%NJYC&8nSP1>MbV{*ws^VAj zI~I&s7O3|;*5&rlQ7S1@eq9QVBT7&t{Rspv@_Uq1-5T?V{HhvpM<0ZWC||Zp7Nco} z=p{ei&(m4s*Ty-i1WML9rP?U<%kQ)V=yQ({L%rDd)6D;3_4Y$kY+W5(p`EY7dG7)t z`lm)7m3W!{Sc{4#;r;y!jS;Fq;his8U)WIORZ6<|%~-#=-RYlO$5g>@-BLti^Pa6$<(ijiRd zFg8-o%=pSrRcY`zD%UL6eTJ&RVnlY;WaD$AAY&;lZww)GPOf(79Kx=8;f#xhj}R2Y zw}tI4CnN;1j58K7wm`KWe_Ak1DnPLIa9qHt-_Xva$O*L8RZg8zs-lOz>HHUrxg0@< z)ZQU|5A{W|v5p;fkdK5qA!xH8-deMB3CODd>|-kX0i?*+cE3ezD7!K(^6*3J?I^dQc=gbCdaR96!AV0VyJ&FVu3H$936T4@7hp!3o~3XMlRQ;-_}os5q=nK zf=b}pQ{=zlfnrEr{n10|lPejClj!Z=9r5Se zee(9_>&<(P3v5U+{J!X823eu(IbT7j2Um#))hIc?S8q4o-IuK?r0%1EBuWS5My5K{ zq{jUW3&D+Z*GhnQWyiemECCo3YKycB^!W@V8nh7iu9FBe!yFe}aFK`kC&Id2MQ)S` z{Lh#NeI#ssIn~G=vhbJR7?*fdh>LD-^jDCT-VWU#b5NK9$JC!==h@nLZ!Z^#IZabe z#zBN5Fzss>0U6t+{Z?T6BGrTj6cJ)tY_vnO z^upbAwrIKKDwqO~`WXFi`U5|NLmVGuIB~R*E*z;exQ;vrY;udrIy-!(m)xDVIuN(b zaCWVRN{0_&wjgSrH?(%Fp{>eJKnlR&T$C-?+`&cNvo^;!Y~# z>zMj)9XgGp$qaz%JBPJbN{GQp&o*kWr^xyf{b9ppPBjZw<5n8oYn-a5ntcf ~LLdpJb^K_yKCU4t;LWPq@1Qi40s@%RD-P2O4q@f2I#s7>6 zP_fL~=yRr*tswGgw5ul1YjJiFF9xdbP9lt`$MK3|%LzLLP~yT;fMjmCY&#jSzA`I40T+zYWPH;o6o>eR(MpA;$o%@9+>ZickJyrK<=6JYU@0 z8J(Ayrue83)9_m&eFpA!<9qJM?i-HxWm2O5IfAR&EHjzN1-}p>AlpsWYwlTpX&??L6KAUPY0qV z3Eq`_)ZZp>mxyYV0COIdK3ScKvX$$J`^(A}rU`>Ul~ZZJnPC)5 zxUK5##DqT=R1_N`fPa(i83`r-6lGtIc5 zjC>xYMN{SO6+-?&m){X$`f?Jr2icBjKg?rynAb1V@j?$G)aiyHy3wxVw(wp=4#$38 zwCU_CCIM=SK|J&B4uI8wL!!R(O`vP7l|cEExlL&(!1`(+eRIW7iVQghti(0CPH8Zd zQBs9&51i?>V$fwRY3GpwOFS-BNh~aZ9}WgSjU)JLh@IDcC zaX>03uyl86Ozuqif)`CVzE4NxHZ?-E)V2hT(7a#zb0riv0TKkKUgB0hCv(ERQGD%c zU_Kr3T0_VhO2llUq|@&+$J(t^IJ~Q!M(A>*HNAzkTbJ}yzBaW-7I269)Z@h7O{whn zq-E}#Ap|w|IF4USyFEk`F@NeF#1`6$;5HYo8sS2nJ~f5kf@D6kEDMd$bO%CpAU6VnNq(=d4I3x*Pk>|cl8ju`q35jl#gQR;JA@kyyW31*CrWC zU#9QQ(|hqOW0yL@NHCvfs)P3+z%F=@boUHXr8L{$JrnMQtSrQiV7scU|1OH16PWO* zNINROf8!CzLJu_$`6n|z#rOODgVa{>UbvGUpb9gROUsH_)Q+SzziK@5WlL%>teli2 zOvI#OZ!aod6KXiK@TFmW`Qxx}@mg!29QthG@8E2^79bRQgq(vb2QR0}JMnt^8zi-C zXe?2k$4@p!5yHv{;}fY8JS7gjj%Z;N@}XiUUB3d9M~Sem7OIg}RJaK9RmYR$(qIR{9Rsp!Wd z4VQ&+s>*sS(aD(-Z=qxtVEwcP956z1g)2yTt1{8J$RuZyS8fi#{?)?ZUOvQJq>FHH zaYGp0D6c^ZXk7yJosirYB+*snK69!axOUvDwz2`sRHcic1e_i@u&b}=!~}$UnmCyL ztL)Pz4QYy94opY?0@(yf5J1h!Pz-iI6PUpF2SHI%C1c#Cq3)y;X%xXS{L~KAU7dIY zJ+|lw78Q-2+hT=Okn9H4E4zh1KGazw`GjA`6SSJBbu&_vlT!6N5cSJT*Y6hOUS-4S z;1cH}L?e)+rywAK%}&!3Qz5H==>xsnki7!Ivu7nT_V)abKj0w01DY2V$n8?&4Bsln zaJssxRrJ2j^2Ii7YwB zQ_Cq$e#kw~Kfe}wOM95$)B3CNsy`}$sczXD`mR1;Jt_o@8>PT9qk!qiRfP)fs0sBd zgt6}xP~S<4d!`ckdS>;fk7DeLRNA!S64t_%RRu}TNX-1RFp>Z}_4IG;7N%B;+3fWG zKNCYOw2An((hX>EA&!5GWsB$QjO%kk^LmLfG9R@lUZ)t83_G0qIB7e;gt*BpPXS4S zg1Xgdj+bQ99h13bh(*>cHmfjO{KcaYJh8}B&M>wJ)}?4sq+R|{S2b$(3!XXsc?=XKFgK9`%Sw(nAeW3wc-k!E{W7MG)nJ~ocl z3u>Frf#;Eu_hXwnB4x3MQGO3iN*hZaos9yST^OToSUEBV`hmKp)>#$XN4y@(r^p-3 zNpyF}+$(f#5AoR-)3M%0ObF3ueA$t9Js>FhB5B41nnp$rui;$)NRqY2w$}W9rzzx5 zf$xOeFo$8IrUfW^K^krCshqlT$wz-g+MSR;LC`*VIJ#XxLu1@!NSf83povwk$KmgG z54|V~2ws>W#}b)C^vzZv>QQXzJ|Mh0pdfdIzUZMd^;6LG3VU`(s$?2b>`jGkFT$I3 z#?2EUWAD6xz~Aj3z7B`^c~hZ|rMWQst7s)lk6j;2YdzHg=9rjPz`G)GlEongvOxXl z;{>4;xz`QS<57$sad6swr_92*eVXxxvS@Gpk2)#3X<)_#W;(*NTkrKNYl9(-QdYzT zJ-!oS)RKI&I}1jLZKL?n_(0f!M#l1Eq4VDmc1R(N7lZN?xp|%v z4>5uepSq=v!0Y3zhvn1E(+1%$Yv&>lM&$Q)wI4b^5x{Y;?0t6sEk|E1TpkPd%p5s1 zz9<6}%2=ki?p{4rol`7r#SqdWBX0fu4XmN z1mlX@@VuYlbvxQQ9v-#9yOvVRz5lsE-Duq_rj5mXxC54{emo8M`QaDljvv+fWiAeZ z_SAT*-Tg8ya^S$DP-lU&uc6;ww$wB15m5UxQ?=(UKhXR2-9WhY!`+G@$}0)Sm~g5v zO~%Z3AokhcLB)?B_3Eefvw<n(Rr{m-en{DibjHZAIQ9$>dMa>e$lB2roU!ZkRsprSeZ=*WM z>ieXpIXsE7x_n`St){J>uAacPLX-QUfyWU$O zDJIetKB4tij_ZzWy~y5Lyk2MQm>{@53CFXETpe?5;>PxvTHatwHTU2`ZQWx7w!A__ zzjq%9%tAP^UqQ)L9krsWTYnH=z%PR!*Q4N9TC%Fs@rf3vK(?vyZZ9wW^DI?Bl(SHI z26`Htav>tE&SiqeHCUQseb4c{wx8~20_w3|ha&+uZ&)q-IO}c=Rk3Ycr!@b#}cT$I7yUzUU&7Qx{ zV8^4kPu`%vk=Ms>!^6?>qWOsjo_k)Mjb|B|E~$Kg1M9#DIQQKbajE&G9J=U$8y)IW}1tc}hd%4HKn)o)V{Ti=jg4Eo++ zia7S3L?mOb|KVY+N7=Dt4o2%$i%=f7LeFL>j2wkh%rkX5+Y(>%Q2&y05_%KgNqjeg zWQ({45Om^ZZ!#QT5Db7X%y-qr8YPlwelcR^Rw@d$_ZnA232dRlFx!ioY3Nph6qtkz zxK1_r4ro$NA(a5%w{hjtx?4V#D!fFg%zTWr%pSGuu9_T3P!ZFM*e`^R{}dy`R%M0w zh=w1AiRt+kX@C1G32`nEu@}bv{f@w z%Vq)z+sxZRMVV~eD+cbT8o=L+CF7_fb1(mVSsKp6M{l`~uM$@N&bmjN z+h3Zku^8EP<8~a7xygVHarSN%IilwFwIF_-@^eqBAEN|1Jp)h#g8Lh4;avKhv(m{; z_HonK=^Vo6DR2_rCRzj^>5j}*rvJ^Q2$_u{WV6BBDl#(r!R$8ZVNfz9=pR{jnV4zw zAwOD72`@FQ8loY8 zeZ=Jg9uw*6Z^*kWG;2@)a)5@*eZ2QW9`^KyB|>`0_ea)4I;%$BY`Eq#Md~kdJT%!G z8CSn!?}1KOQaGh<3&~5Ml=qT_k1wZy4ARfK?wl0ZNSBJl>nk{N15cB-hu)zj&i1ZZ z1-oC?h3Vb(*#!#l3R`lp_H^nXCCdo;opU@BxLJG-6Ug^yl1wD=$2Q@^Z|0o9hZ}nX zp-<`lC;g1wIhnRYGZ`H3@lwt5N_|5SsrrWEGEiwGe3^x%RQX8_CR{pF`3VT$`+}3z(OCl_@N?>Ao6g;@2O)diZ2fl5_vKsv#tsZ zV?-0sDBp8d>fT7J=;8m)AiZy2-_|yq%3m%F);M%%qwdy_8zmCoG~f-#HJCB@HE?Vp zr;7&8tm3P6x@T$UQ3h|?tVf3l!x?`(7~)~Is_h}0N@&WHsRM1!qJl0-|7kpT3rRxn z*@^|1LJ5R8xqM?NyihvNU6tY5BnCD)AS`zZ;lb%M>7U7jO@ZvF4=eHj*HXuq3!{qJ zGg~~H)Kdp<{yMM8j5e0J8jO{YFm*!NKw;hYwYeyau-L#A+OdqvNUhH3H2Oz&?miZr zoS8km#|7gm@uiSisZnBtB6Eq#5`TKJO;39D%To8~SN}aP*k2r0M3#qqIh7G`odndNkl`N`ph2TjE|2EL3q1lAM9?u`~VFfL;>8AN-i zR&0)Gy{e}VdW)2d-CzFE-cE}_;n27jyDX>3ICPF4A4TnXjsVn8&&X4UkL7Ev$=@Ts zYVU}buK}E@+b}69t{yB5N5ctr2s%|b$R2QgLkeP};iFAR0;1!9cc$jM5<{(_mEku= z^sHX`-06$>)jPN{<3N0R3*@Nh%|}H{)z8|puOd{} z8}|;@PyCP5gMjB7grc7dYYd#0fC|FAhwQ&it2s7Et*6;4nr`E(lJ5$@^+gV~@S8Z) zY5(Mx2{C5C2` zju-k~IS>eRSj;%40YG*`Iuw_# v32SD9iR|ekST}`tG@8sLOCX52E0Ui6lJ)l{ zpt(m$ObDHqjFXk_AWKK^cMa*kfir+Byc`x)K0Zy{H(UJ6<-_am74Y#*W^>#a9*PJ=a6iFX%GLaK-}7;u0DN1EKHQnwWPJn zocaT>2$CRVXHm>e_cO%Ookvdp*y7lv%cb-|%bIp0I%<-7HtabN*kk!)!R}iA=cqB{ z5!((A+*;pLIIfwqbIF6bwty5_+)km}+OBr4PN9RZ!8{f>AKjiqKA~iXLly&`fCD6; zW@&ApEXqgp1vbQ@h_4LsiY<710WO54~Ywy2w^(jN{-4{o-Jy0FF_mQQOFg-8X!WLe*3v=u3b_ zTIkZ~Y_j_tz+%LOI1&U#Y;Pl+$D&UC9{CPq@WW|?+R%I@ z07Fc%%m>oze!K}{z38c>4V2OAX?h_}uc@rDPi&VOWwayGJcVgG0^fMZHFT}-`AfNG zP5!!ObH5&u5K`lP8G0OfrRDc5Ddc^KgGHy^!O9m?siRlNeH_8<` zbK-g1oORk1CK`^PN^R3d7)p-fy*Lt%Y7>FpW;_X zj%^ICGA?F6_u>&ZTEzEK;u#cqaV26|c#4?F-$lFm0D^>5%>kXv_!%HONCOW>8 z1M5lQZ_^$&u8WpB4DEp2N?{X<;;mE1PS_1lx3#G9;C$-(AUtiyp>M24l_lwzELW_` z3wd;&5A>2^9Ii5j&V#9>-)bBXdJKg83}uD{Iv(7L}x z{o5)g+dDCul>5@rkveS)*>1Dtc$+D$Q*OS3vg0Y^ z-P(IjqBx9x@uL-EEK=5?_o(Ly(~WxK48+L(0jD}aL2=K>wJRx4%Jw%?;$ODFk2B2xLAZKOZ}qK}z$OpJ8|AP*~t zQYhU?it&NoRGD+bewNP>p`0%7fyBm2ZB_)8PVt`ys}o4vH&*MtnJJ*V>Dz*%s?jp* zcuAP2l_p}*1;vP(gchAum3gcrE(ES2n$tDi@r9!h%vT19vHkqNb6KeAbEU-N@ z*6B8xK%bI7ShEGav@_OTekC?Pc63yF2P|h&r7hGY$ zlwI*1yOWZo#4a7I!2FhRo}%0mmvMazn(EYLnMp^NnAt3WVF(MNuPL95rBD6}@~LP6M(S@D>hk|8s|>(Q$>Gl__q?h?lj2 zY+K2f<|g9ru@ZHR)-{Urc8_U>#_9kio8J3Q#wMK)i7ap$`s}wy*_9sy41cN*;cL*w zF*6iZg^JJwWz=J0$9wa@6P2$y8BbRM*f^z0P!$>?Q zj+|MbNs;;sa~)GB5Wax;b1cMXR^j;20{CgdYU++s|85F`JUB-)+PxDNh+1)2I;11< z!CPQ-!BR7?(Khf4`XW$I8L`HAYvv;HDqR(@H`)zcR>O`Q-UmU@^#m`zB*ZABD!-^NsBfE~t&H;rHkH@L{*!%)`%r^-y! zyH;lXoiE_3yE%?3m1O7f%QQ(d=4lKA#KJ6-qond_ zJq_;eIRdB0h-B|uO)!^p;LzA&uQDTbXVQ-{NE@8S>Oz`nsJkVuvL*l0aKrj8+xpLV z6Hfg;beFe(G0$NQAU+j)l?Q*_&7I3e2CV~qNT;50 z(5l5?nhuS62^UdSml?G;1{kR81ld!&Qb}oADyDL^zb3FVkXXM`kbgcKVn=9-XO{z7 zruPI#!AU%dllzcAf2#t)0k;D7vmUIDN&+|I&#Q|8tS~D9^X}5=4x%cDSt|5+Iah++ z!`TH0vnu4`y;xs{dhab+as>DV`wbhLvq63)qy3$y(i(rLb_fWlDdgg*`7)r;X(Jh} zC-(8h`?}+$r*Nn$S3d)V(VZ?U)uCekYx`?hd>!-v%FdODgR;(Go|L%j*v$F^M)@mh zr0kb;l=Z(xc&C=)S>;$8AO-JlcCsc+Cy6c7A*$?Um5j1y_DgcE-fR1t(&noHtFP-Grx zGmd8endNlW&WizH%2@WURC;|%dAZVIT-A>qN!uh&?n|L?tAk{N2CTB|7h2tZ96_~! z+^b=Hw&Z}X0JY-NP1Sb(tQ>j>{c>?=327pH0d+oF)>Z1sPo9e{YHjI7vAJ+1V+c!i zRc**$;;Wuq2T-yw?f0kU0A0Oa&DyvLb2;dHeQ%$hQxZ8F!Dg<$dX=`;3t^?cKls&k z>=5b3;P4w-`a$9#CzZ5g^)T)z{wuePOn`{U_Q9HA+Iu zwWyJ{$(9+frZ9ck=0_jR%92?bY%|Q96m7;+Z%1)V1@V(LP6K8a)1p``@O(GTGAn01 z5QD|;+7%T`e=L((kCWa*`Ctjte8Z>~#~(rrGsc%nP`aP*HH4DuC2;0inx)|YS8pvj z4HhK46fu1mNxSrN7U816(}t@G*q|WyK5P_5V0>$hadNXR9k&$c_cLwx)6(_i0B!Me z>yp)RjdradY|DKzCPoazkZ#7veoHPaR74$XgOT64d&@WJp6FRhg$Nw%| zIB*189!AW0SaC|$mA#>kVC6_p2%oM}D2;t!qKS#jHyTSK`rq~i;n*BxI?Tp|eE1Db zv7v)n3&~-%N;47+zVTE}CC58V3hnW#dqt>pHliW&7=wJlxF;QK>}b~ka}iBwGRtok zNrx-f+zugrcd3ji7T3B;h`OtGK!!+i@n#2SB|H()C>1dtvh>}`R@80WK4Jf>*nW*h zq);D@WbPwN8#08MD1}9cgO+3jxvQL zkzi+t<%yk=7N@b2}ce);%{ngBsy9Sb6%lPlx6b&oal4Mnh-W1 zAwUj0^LRlf2XQy33Y{0PUr!Q(>24fEr2m7-ae!$$#6*aHNm}%AG%}UI@dw@1KYey} zeN#9{dIhjt+b**n1kjJ14fe5M;gV~;VEj)7gb_?bf2VDz({ut^eEn*IU$Ym>a?|Sg z!4D1-_M}U`T3h}M*fozr*TUyP{uFZRh{o++rkYWcg*aOIy-_UjaFR0_PPw0O!e@Im z!8$$0DD+FXnqNFn`(vLAVyA?|>l}{;6K7n7%iQjV=cWb`rqQE{l1E4^pbZUMWrhm` zEu+jIf7-p1m7il+*t9oVYz(d2hLojueZN;>5KE4sH0l;H5z2MY?z!`H;1sCUR7a`+ z?RoiYHl2TKfPx2@IX(ooH1XDv$bLA&1!Yd-MjY#bUZFUbgxV}TKbp)RIrD_bMFf?b z=j8p+#2p^<3B&rgk8o1Y0*7>kvkak4jTMk4|Dzy*WKPuH-gW+CTic?jolzzNMPlbk zL^(Q~@2>2#pe*?Oba!i03oT?HIfBJts`ccvUhP7Jtrp6T^hXDfi^sJ);SpsQ3x`9a zM8tW`rko9I7ssuSp_GaXQI+?d{osca2}Tt*#VG2~;}-YQ?|sCw$??of?0Vor8wn>z zE4kWAb1g=qxCr%`7F%cF_nk%w6vFx1@tZBi-MXz%IO7j{<6l=AzRqz)5?D*Z06ib1 zlQ~R$uBM-Mzpkz8Yzz}Jwg1D^S%$?GFj*RFpmEm(4U)#)Ex2prF2UWsahD`ma0u?f z-JReL!GpUyY=5&mJM;Jc?B{mfs#B-l(&W?>m8zJG_KuOTf;7iW_g+#5BXxhV~E?b6<{->a_WYljE1O|g&5eW1zdNU zYY`x|2}#v26|YY(mN#EBK!hV7cl1y1Hj`MfTY)wJ+nkK=zYfv}tu=_+n8l_f8c@^t z7oX}O5mkuRYPmb3)5^3TK!x;QEJN<6qc*Y_#FhwHHG^aiSo+okl z&a*B>UORJo)Zo~O7RL}po-YY6o(Qv#JuPN(QRVj2SfIEpQ_0}u`4=E0f>;*CI*GKaWuR=Jf{i&P}`?Nf>u;)xS55yD;r%sOjbDK)m#PA5~`(C7^6m;;#>KP4S& z-`uy*n4Uh#D>v{aVlqW~X1Aytl^kRuT3HydEG!It;ZnVyQi0NEf{=L?qffBKnxbUP zL{|W(@3O2*os9mPDu`K_edt=gonBKE!f}rDQvZwSLcl}0){L6xLhM=%u5e)4?5hCF zQSJVXa)@q+Q$yC|;zssnZtStna5ZR0-InE{C!4wqCa6fL9Q}94y0Sp?RpXK{9I*`z z{ck@)``*VX%nH9ong(=r}SF z#5`D05@HRM@YFg7msXf`+`oj{PgZ8K1CB|kRvE2e_5%HzR@n_@@KX7WgN{Tv2E~UQ zKu3JGfvJeZx8L$-IBHVQ+19q3GA{uU8aGd9H?*2| z|1SxBH8BqvOWF@*Wsn1>R~A>RYPGwRULvI=U$KM=IXI4bwWKINQ3G3sygWT{mUq)f zDL}YN?R4HfDz+VnA}?$a+72TN&xJ1B;;+p7)RrfyAwrScrau4mFsaLs(P|%I^V99q z?9$wn@+5qyUZLF9Qu@Q=g*4An0OOK>^Ja&UK)u9-Gi(aNGDe~>l_PcQG4NG>EjN{o zD#2MY!fNNMp9xqYoXSLS7?iH!WmPRz`gtx@IG8&hbX2T!KFgNZHD92}j=#@po!cJ+ z9mysYcn>?0Wwe>$w#C3B@jFUOtN$_HemkOi zI~{D1=U}v4QjFCKUTR|39{u66;WlZ7E?*L zL{zz-kEiZRRq=2Pe0J@M*{rQ5W-F-0q8m<0@5}{9$xmLk9?j)b{GzUZ+(ZT4}q_9-5IC^<=@DI51trB+~gj8OO&e)LXyPv6Sp z&WH+H^~N!p{6HGK2`yJ)fPe^&fMd71&HCYGlv~H*rsN6x2rN zsuB`ls2ktrjYGm?FsYHC%~eV?g(LE%;nW&xBRLEG$DNDLt1)>BH~bb8S5SsHYIPHB zs9lgS1oSsmAXp&(A2$9Q+1}okA(!dN>sVoRxqWOHkhf#@S7YK4UkvQO0rUrskQ>>0a|qai!ZH<1X^mEyp276TNe}DZ{<=I0 zqk5EE$yqR^Rm@rS)4kuFqJ5fH*#OMwRP#&ch?@z`Xyxcc48ZQ&Q8;BnqxYdP%Fa|= z`KjWp)K*)eBk2!OL#A3=bW!$WhDyI~gaIh^1Zbk;{3>+uU4^f-QW>H4inN%fiJ~lN zbcj*a0A3%h24O9-KSXDpQ8%hI-_sDtjA3L*lR(fUM%{2m8Rk`$vnTQmu8GNj5??38z^f6^PoVVOEN`;VbG9;iZi$5Z%zxB^Py3B z&+IB&gaSD1HQq%{Mr5RuH}moeq~S(s;(Qy)iXqS9YHCzuNmndp44suU1t?Pq&qWWg zR@5kaFJ}+zcFJ&fwNHM<(Rq$-xI$HZMaAq6tDli8r9l)K$ivH_)_ffeM+QNX!1-fI zNACJ7M2FO)Q$OW+q3&BsGGbeeguwNosaooPmV-e?2(z;goM2~NJurVJ=c5jPWlh+x z32cli=38ZNY4Gf+@E;|MIMnjvEihkT>Ge0P zF=Ddy{_Yo{n#vlHt4G3GtXkvr)zd%J=Z*oa+d>cqFa7a%zEeE#h`iHWaBm@r+yetH zJJ6q2Be#A)5|qw&-d~>Hqj#5rFkn;3v06KH{}#gPq8s$v4Zy6>IAJNAv!-B{(y$?q zyG#dnySjnpVQ^xl%;jziF-fc}JAhD5ULY|&xHFi7FuF#TRI>x_7b~)u-i78(W7 zb`LIpF_O8;Uu}vh2(hOhPFt=m|8QZYd-@%Ju~9cDJnL64jqI!kuhyIT(0wYo`QcUX z%#Ed#t>K|4Di49CIn^H8(fZ*!L(|CXP1Y?xx zl-JDq&Vo1;RBzYT8}=yTkWuYP`9knGg?yltx*T!m@X=w{ovTG5fX;(ax`3B_rWz{uW7kKcS`DmhT`u#JlrA$x zi85L(_|AJ}!<6lbI`dXBGztj)!YkQLMKzK=y}n)YWDZ;hmG!`{qpY3~5mEPATU2Tk zT(y@we1T5RPl$!P9p!buXcKu!9bfCMYAIO@Eb$~RP&(8kTVYOdi>?*RFO811;ckRn zg-I>tHm1FEC;ZXSZvgoGEUG^!0?yX#zj#*5%3&hT($4YqP>xxbPud4o^8>t{1cc`l zU3p(`J89qiL`)T9x?E<-}ru4D24VZ7pR1^asT*Izlzifq*OIEQbjM~FL zwbeidO@7qRc;1RaPKyvZks9C9Og;3?&n?%GtG3tm3o2y9Ji|6D-rW!h4SI$cU10|^ zeAZZ=C;f1BU7?Kfuj#}CW%scfxKdD9&Q%>?jt~pjS{+MofZ%Tk$)m6jdLuY+B)aOs zX#0h@nFM(4Fuop%eU#OBQnlMLB#`vS62*;3MacbEobdaRO!l17Q!Ts3gI zYoIWo->m0HwM?a{H{^g+mypX@jDk?kCIeNAsJ`wc{hHRVGLKOd$qCGLX1(w=HY7mor6OzceWiix=x(Rjyxq;l=U*GBA|}otxxh zz+Zby)1K<=ujE$IQt$&CR#@1q!)Ro~M!w*E;S-5#ez)uPvo@3H<b7@_#H6MKP&Ey zuuMiGHPp=pz|0V#k)YzcC=@y{8rbFvm6H_s?k;tV-dfbQpx?eG#n6bw4%w}cC?)4I zCMx0Ld|AoitGSABogViiPedAg`9y)P+u{n#WC$Z+9Qa$Vh>3&(x>4T?)3qK*a8zaH z9@Y}-4G2=V{u@5yJ?g!QQi@)z7WP4YBP2EW4Z7`hYgMb}F=Q|DMEsKqTWpD-L{c#D zYy4Eari?c!r8~U;LYN&v!k+-OJ7Oe}L~Mu!^019j`?0&tFsCVq&3`XHidr`({JEev z17_4gV%eh%ely%l>K&O&S; zkxM?TBo@0>Gga+qG#aT&1_|=}PpllNr|4aj&*=xztB^#_J+P+X`N)`cuKc2#jtDMbSI5R0ca zbI|S=5+5d*5a7KkB_1q+{2Xkz(+}(fz^fwE_l`SVz)fcbm$daIl$nYowzGCT9a)=M zzqlI(7fk~mU~L+0;$Svhx%UZyk+cff2gO1?=ymP>mu+`-eL?Kr@yRn!bFXVlZykm% z&?|PMvGJ_j(S^*h%%{Wsw1RUDG`mp)PTOh{z9GJOBwbS$4%~3mX6OQDbp>m89(JNu zR_*faq^~#LDP~VQdUbVtxxY~9O1_@-TNwm1SPJwRonISGUatOh4B%KJH4^_{fk z+GA7cwKrn_E_|aa>+JsDK@*#yP}=L<@2=&0zqSNe|6?{8s{QllaU#Qw6TiTYg!+Be z0EV0xs5`lFDEj}NIJgcI5ut2xFwi!?TZ$R*PI@hg?!JK?$~%gB4c-99WzFL2WE$OT zIDaHZqu)Er7}+-&Vi+u|2hkQ~0W}+8BSTjs9I`_odke7hVW+|Ap>WDFTdVd_P3#W%yQwWh$*FB5L3z za{S8M1#{oz@ES~8W0@aN6{Ny|*PuL{2~TztC4%{H2RUa2fxFtv8aeXTx~_LP3MSg> zekK03bbq*NwVdNNQ?p%{sG?Sv%zGmO$qcA1lr>U}XJ~m{HzC0idC`nKuu1}Y;YovVk7*}Vq z$05?UEbUgv1s+`My!Yw;SE=sQJYn^KsU4ILYNLU5%#XEi;Dad$d|> zRkUqdv($i(-S+sto{toqM)Nd1%+m+ty;AW=;zF!#+EQv=w8n+1J=?Bq@DwvF{oVan zw#7ZMVs{~ZBeF*2#!*U)|xbQua``CkrMwV#EJw1Aorv5#d)R`9j!< zBMchYM|0`31XbKoE+>!vn!OxH9EayQ87G?uc2TEz6$YwlTa#(1Oyj!SGgK;1KHJ=q zcVRYiAFR-w5_1y?N`yVSDOx(=g^HfK_ADGQYk<_i=0?-|{Z_ z9c9NZbvTX`c`X!nDlVOg-J0+lckCN?kTUV*6NLQ^D!5+O9gY0t)|fZ^tZtwZ1N`~W zl{8OF&j=IBDg=L}3A#z^_YV~+QH?J^?cB|FSB+O`-unEDIt``mY5ob3kyK%000KiF zF(J{ky%y`mpq(8%Oe?YQQKPxEO%Kf{!&w!<8x2L86mJ1tbi*@;LRBc$F(489zWdH> zt@}FP$t$cv4P3)KSXux#jI|QJ#*KQ-QALW|RJ9#SLf=*h?vx0VI1~PJaEAJ{y0_~0 z9)>-OZ_+~Hc3(p3*)Z>1)v7D)t@f+U)^OrF*&%I5$fWZVG7=h#okAKpE56vf4}0MS zvM}-A29L*~P1kL-x z8eFF5wh@G_HAziQICh2v*FjoD1!?DQWUmIJyYbSEicJu>5alu}3{_arA$+e`^7OZ8 zVcRVGBiNlW8*{_P);b)u+t(RfFWviuXUx>WX+;plU|sK0*6LZ1A~Dq{R^s4ba(qNA zD`Ee0AuXfQ`B7Nda>ccF4i1F6M3&`rUXKqz1joK@r1D=PV1t zuGXm4x-e|Y)o1?GBplT{WBGb%8#RPBF{*V7nFv8akk_}6S{ZbuLxC|FSLW`Bso`P1 z#ljEP%N;$Gm*QpG{7mWSt8k71?lR&1bm0uU@llnT2dXljwvvcGrR~n<1JUnscsg(b z->xUxXN!qBOWC;dq&Ox z73}-VTVRBfF?z*M&8QFl3%#=YmxrZygqFEoDRQaX1+pRI@;zG}C4Y~*H`U5EJWr`{ zInI zW7M0y4*`~vPwdv<9!+ticd*Cj&7>nm%B&?ijRk)1W9fhaLdw{} zmbLuF_OMG{=5zhC)FG4`xiq-x0B`VmqHdli$|E7*rf})s}fgg5myE z%pc)IohR8wn*Qbk=12M$miBlT!eh*QM}VXaV>kBN=J z>@bBtG~+0>E#k}4$R|spAna+js?(z1EE^g}GK%i1QyiGQ^u*b?B9o6=(5R-Ir3BFq z?hJO3QQ)tC!1%r6)9$~XA@3r)N#pnB+4YLVAQq2FzHs7se0BG!_Ar)TJhA#^pTS`_#`%VTq~wr}y-N9^w5H!S%o=&zu))h0 zs@gP%3iYx+U(TLaqz95tb`1SXW-W{!k1eKrTTh@_Yv}fNur@5n(nFubGXDsJbT0Hb zW!d!0(Jcg5+zI8;w7=KI{ziPu=2iK|2_tUhfch_}XwJs!uo+CpKsAs_uUU4}a9&H% zyzQlFD;!vf5Nt!`88$2~ zp7{+zHzc)h{K{&NwdSv(6|%0Mk4iQtztMdaq`z+=K$9^JT_t9-oN^Ag^MPJM?pR6} zeEV%zYG{j|NvLBGvj&2@k{UWay|r)pp)@hFEqMdpd+hn0EgJ_ez2k?;z8)ds_t=JFVS4JT)N3fg(oCFCi4wJZK2W z?c0C2I1DnxUc(@}?As4Y-EY1@XISM=Abd9G!g)(SlLld@4NJDX-(``u;OMo8*xg#` zWr9i~xe~dmc04ftq-c{evNZlbRP_ofv2mQSctu_73y>3fLB~~M!^XC3Iek0ctsPlw zdVOi4`)YkNdz%F8_~}_QOC=qWAQo6A%lAhUo46!ADGVqRfxfI~(s50n$!k34)Xf_B zqZhx<{(DO0liehtp>?Pjt7>_oIk#USHI(hptI+o%dN1ndN^hAVpN?xqxmM!K6%P>% z*Hyggrn67VuXz(paGTFj`6KjH*{8^JXuQ#R2oeKj*a$!I0=O3LfZ}wHS z8%D3MGUuX!?xbWZwttG^mfpLKCZ3i|24_X+8LJ`&^Wj;AaUbp%6DQ4a=(Zx0P>0T| zC2l~93mK8~nE|Zy>@=k#jChcQQW^vxEyjGs?J!=w_ite=&LcP#_@x;EH=V9kCV=$9 zrne6Xwld%{@mnM4fZL!Edee-uLxoR_O&fOSAzjLyD69#i(T_%+L1VV=#$}zVXk3kk zkUj4(8TLnCqBdSD!zh!s&I5b_tev4_pHKy0QjUtwf4Q(ZYjp(So8nKmgi+_-=hA*$ zqy0f_EWo1vZ?9!;e^8Y~7rP*R&i$K+a4SwmGX59PGr_RVZvK~g%YKh ze~VJL-uK6w1taja=F%$wMpDHJRm4O=(OHSgHj3P|>QFc9lxEoE9C{yx8f%^f)mo^z9b-f9ac%!8lqwzWyU_ z0s7s8E_1oge8pFan(<}ggS%+bxQBk+MSH!^`)>yX~iS!U`BJo`+tKQ!}DhuxO zC3#^~4jM*1H*BmT zakqa~& zGgzb$N4pgwLJWwOXtDn5kSu~p>~JwgyLx1OJawgw04D2wt4_sVh1F29RI*E=Ra(WV zipk6vCec6+cm(r0P>hc5I}FLED0%=*nMW|9a`cOgGSWY>&mXoDyPKrTiwKPkAw(1g zg7PZK_7QeHi3|+#Q!t-Dd=(0SW+<4WUx}s4=r!2mQ0Iu1SSm zUYpEZ0|{uQ5KCrllIdEOv+tpn$rhFy!LnK;DYYE5SQcbaGH4!+ zdQ+fPH*E75g?(*ENy3;pmB+uo>bF?YHifR1(HIG19jZs#1c^BPnBA+!sOLW=(uzU6 zerbB*2mu!-j1Z!~8W(1H$rEO2HW%B0b-?|p!Z2nUl8&n2W2ZEH=j1h(m~w&eY;iG0 z#6>O(KV|(rg9w{EZo)bZarcD_OViUag;EG$JWvRAW*1Tqgn9&AB2bhQhGLx*=(A{N z2|`|52k>&|2WpV5ROt|Dzi6|Me%0`;G+{zEo*%K`8l1ubrFJRMcM(8aOB|l&7_Eng z2-<#UvGj^S76P}70ey6!HHNklc81ZR28k&v6vk$J4T47~Fz9ZdwG=Lc+FtM^{I63+k!F{v8Kfga=*1wFW8HaZ6~S?M2iUDn{~X$D(=zyM<(b)feE z(_%}2e?d-u(%^^Bwm8NuSTZb|QBy{^`IOCabMTM1&t${kd4}8EgyA-fF-ZwB&Y+o% zg6P(md;X36o>HIaCzTAfLiS{({r{+c0qStqNjPt}U2lsIr8!TZU;a$KpapCZ2EZ;Z zE-syVJY1!A#fsbwy%D|57(K~9Y!h}pERdV61soLzpom=JiUb8-JHDYCcKC$dZv>JD zK489^ygVel^9I~V2i|zju|aRXH~N{9YczXbK^LR4)mszh4~HR@Xx5y$31B`eJelXJ|4 zn87u4vDI?7BYO?f2d%A#mokJft4VN>3&g^}@V8yqdXbDVrhnERrvUI|I>U(B(% z1lKSVk7zBT%iN<1x%ozeEn;@^(!4@uZuh}w+IZZIBy(2oixidLAl>tbpbUTp*@_gU zLg)?rLe?Q>1() zRcMQGXEd)6>M(UBcP|rc-p&}jaafAx`#obKU@1V~2Cz|1+WFg!X1z8T>G;+|H#vP= zYN{$E5(_5e@o3Phd3tjcaDLU@z^|4cbA`2s+UrJ~e)0XaoG?sNr|a@}KQdiIyZ|Av z4*je(8kg8268Z%l6*;d`MoDn%I_u8uROggN8w@Mru(D3eEYCg;|E4r{(Ub&SSMG_c%Na)n-km$A@BvYC!ehI0JXUK6#zzgDh5v|0KvY2%Ot0~(73 zi9C#YW@@^WC2lb4!yfhTI7)y0K~&wSE*Iml0GvDKjh8Mp>KV2`++aK^yp)_}qN0nS48$+_nt7 zv%G{p66sfd=~v#Ie18;q*Cg*-HF_HhB!1r{e+jAU^1m%N8c=@wr@Wo>@*^;~>)P`T z<89RFk)ew^{&FcGg0uP`^U2#TD8pq%TxhJfx^7H6Xt@Cq zWwnjtj10uwM8i;Pq!y>Pq%ts)jQ7?lKwODC2#l_@22;q1*)u zu_xqoYAiUbKnWg}L}!)Z-`=B|!am~*O`VlCJzRXo*mYL!9GFLDBy_OK!QC@umhm2LJm|oA1 zf%`D9Ffg(bVjAW#fc=S#1{85JC&a_sz;Z9+%9|f$@q`@?KmFC28g%ocCl@Bc9lF&6 z9g`oK%lD^(T@b3KuFKN(5llumTf7mj=RmpMQ;L3M$i;Ng4%$e27_v7c zXK&`*I7Hp-B~>)8^sf?bN;Y<8tCZcORsJ=0n)T7(8Uw(%KJnT^R#~(iSV8Mc6I)*L zCu43rcosDPT|`^36X?K^(^*2Ne$*QO-RTdPm?n$RXVZRoSRkt^3Y;(ZxZ zB1eKK_Z$(gQ0H_$Sv^T&U-mJ*DB&MZ;rv!tbM#T~&*_ju;xXn0TNJukX>El_MnWNL z&r$6@KOr%VXxikbNYh^DVX5Sm>b>yKhq?qrRZry5u_{2bAnLH>!Y(*+V(6Tcul~dh z{g*)TQc3ui8ewHU@QVisZW3^5JQ5~~yyx-zQG##bc@p81a*3K)L2wXmqx0bJV@MU` zla=IO72Iq_npqs@z!Myx`AsBkF#YM!yIWDWqbp$a@o9VfMmG_B90J_{2}Lo z?v$-Ia|{L73a4DoCdt9NGO^jm!AaWcY#c@{2jo(-_92{W#7>qXw40k>x81k&m6B+b z1ms+|X(-I^eIiW94Vy!?{(^OO&MZ}Ja*QjE!HGw~aMgFEQMeyXq8`v*wVXNpfmrv7 zm#mhil!(ZA-EJIY2Klt+={$4$=>uW;c6n#FUr%l&RY?3f>UQ?jM>l2&ClhK|Z5M3H z!&2w*ildxyfUhs=*Fo~vUx9dmXOpjdFL@$25f?3!{un$wJP)bwS4P{8Z{uB2sVqj@ zLjfm47wf*~Tgop{B9{wf@Gx(08}H9tL~lO=uavhPUn{%9$RC2pyC+}&PHs8A#B~Mb zJpRn-F?uZz#5a1HNxiUqKgsbgPk`12Brfa=wh)4alg@g@NLO_(nd=-{eNC#M;g-bl z_}FHMWSNTvMPpO45bXNUKlU82in_ z|IR}v#VJZF=|bFjFd~vX+(al<_Zvs77Zn;0iqSb{enuf9w0Y!!lEa}fY~turUaH83 z?<8r=O_9>QYzZ=Yn`h5Ngk6Z0xy(AJi)bWXeoaG%d^?AMKSd>-{Hlju_ld66g}TP2 zgYVx@vp^m9*j_HMt!v_)Z`cRE!l;Mb+Ex7EAz>>G${-4HPcmLWxmPsgtC*+14J<*u z3p>#{-)S>Sx5{suY;bZ1fBuxxF06~gQFqy16=`aw49`b`DL2o8jQD~e^+Qe-i0*5t`N*ktoYKg0-K185S>lopI=tZPDb0|m2bCwdh96n2?c0;j-n(TGCZSr^CsG`(* z_*z5RvxrajZHR{cZzL`qj29t3C@C48VBG zzLG3iCXI!7rvZg8yf6R$E_X7qAM*0EycPB=?;3%rkoM2EAvQuw9YwR}LwgxTs@O?8 z;D9MniMDk)FP=+D z7-QCW#q{5U(V_I8n~+P#`j{K^MP)4><;NYDcmY453?YTM=vJiL^v|^qCSH8hy7@Bz z;A|bN^{<^TEzjIM87sbuXhc_LEs^xhk$cb_0UvsjOm=-wF>EOS8-D-J)IyV8Z$Vwu z`Zz-n|JOpbzY0Xi^rZfSGbM=+7Ug0;Z81e5PL>+6R1}BbD)LX6e&)ARe}&qM{gK_E z*5QhwSNs08J-9BHM>PMO--m<+f6~-No8u48kk@+V?@k3Q@oVS0fSiNs^6Zsg^e8&Y zl59oPQ2z)4wcOAJY$ZS^UizX<&v%}*id3F!%YVh6ar40w^I`p7_tV(|dixn%S(VR( zADc13#lO&^t@OCZx8;etC5Vg^kRx<(kNhi!%N{}751HS15afa#sxR)HX5L0f2ite} z1OFM~dRSYT2AWJqdlE0HaH*Bb^%mW3`F=b^JlMP7^FL!l)pP~`4e zDBvL?kVxd-RpfqwY-b>b@L?vkGqkNu;N_dhmGnjR+k6*Xb!c(?5Ou&m=>UYT3)C*i z`TN`X5X(z1ORmx9Kb?w054ZJ;)kZsy*ZVLKt!l%qd(&B?!ow zv~cqG6lst>`Mz_QT~nD{_jKNAt-C>goYU-wvpK}%%UIj_3E>~i0w306c!l;+h(ie} z4AZ&dN=M`=z>`A2r&WFUv&U##8a6WYM%&~sF4LT=qOI?4ydXeuynF-tpA02n_;Igw4A)&JA|%b?MR_WQHm&vpyll+fpTh zgR~Tg;)Y&@CEggWh>hfmh%Afa9ge~u`LmJSMTm_4puom!PJdmb${oc9PoAlrJ|*c@ z-cw?t4|X*Ud(=m10c;z5Rg)A*kZ0AaG{VkuKP;RvQ-J+=81et6rE-b>HX!{MU==LeQ+t~9T)-9E>TQ?6EtJ1Z43eo7~svtv*q+vrg3%1DDBfu|N1b@&tUyDpPDk*{ZU z@)0ZPKyTZq@GPzC>-w3;pv!a~n*P>Ndr2KEjVe*?b?S84?-@YSa9Ylt)4!1mm#V)v zGt%NNRw@Lv4fpw<;SYa^TNz-1>(sRbn%te0qr=&g)t@3glQWVD$5z;vrVD z4<6qc`qApBaEf%o#N>kt5TaFod^fO@-ONoVxPESv0_tiVj(_`P|M-E)3`mcaRP;63 zqtN=mmA!K!@;UbH>%vjB&TUKez1p?XrAn@vdZ$il73H7umOPQHZfV8BgjTbOcPaYd`p_+RQAW>Dkk)wh&z~oN$)SQF7aXGSofApSgU*jUOD)3M|{@g_dk{#oU_199M26> z)>rbgi=T9!4<}~??{^GFp?;jk&#;U80t&3p;LVLUk#|QgyRP4-p1Lnr8DFd(d;`zV z{rilGU;^%;(3gkbNnnq|9- zruVxIL>Rwa2BV&?2g3L5N})ls=d5{p!gA2jJ0Jdq^)y-wn5qDkYtxCSt-moUV96X1 z#@xegg&2fc9DBxWb`3IVXC`upw%@!h7KjE!5`=D`4lV+A7@+x#V)z+Ege-tH``$h9 z;2kcy-Sctin^LkmGk6Z+;s44);`S}=40o%01zvT$&hAv1i^b|^OOKlIQZe~*_gOin*B8p)2x;IF(8)Y+ zlb_sXUoiA#gE7C{$wPrcs(e=H?N$P3!V{&-s9eu@GNmeOCkbN@qn&;7^=0l$b38*2 zts@?-`)@c+eMp>qNLYnb845VdT5oEh>g0=mUdK7RaVP6)!TNfa2_tExU(0p_((b(D z8fe?nU&uC*|1a|3aqL#Z1Sv@*Dip`%^y|aj*}B9q+Q%)!6H!!ztK7-dzG(vuAcn66 ze(~5{rtLg)ZtTaaMjjKsTHkUrgV&=LM1y+s{*b4Jp^jdc&+uzPd0l{T(s_<0|1{@I zlfkVdvjc)n@yTOWTE-Oedc9%7`7}~6J7tn^S>O1+d^`? z#!%X_6-fIAGZ`w{E(&M)UW6tZMD~|SUe=Q5ejTX~gZLy1m$lTS(7%si9k*_dd^5Jf z5GGF9Sp1$19$3eTf#gFTk~ExZBGqK!n)sFuNeuDtt{X;+-Qv>0haA}wb)g!H+SL{7 zx;X@)J8FRoPJyE~lSO_Os{La=WFlrrGlKh9#^C# zZPX}Epe&G<*S{?8cB#3pL4E5&6nh1>{!kFcIm+O%{_9E|5Uq%9?q9}CD1;pksvA+D z={%b-gKB)ZF_>6$H2n{+C-QlUBpM_$S&+v7wzZR|=)P6g<;Tng=w?3aCO&~NHxq~! zQxvQFcFKm^=(e!3v+S4tLn~A>-#94L5Joj|WdoEus?$(gb5{`l0B{CM;DlKY?h7Ll zAE6lw%K@tz%g_Sx+Hred9r${@(Fn8Zc+2(%)ncF>$$!mSmNktfG00>~_LGyVm2GY^}iT4@)6@e2W5y(nP| zpu9J70w{GwGq;trGKIHV#k+AZXtevR5A4nhZ_ewTo!*_!!r3PuHZNB^|DnY}E3njo`XRJ5_tB4Gyq8H=oY`H$lL#o~X>4zC=@NalyXFU1F zUmPnwx+c+Z8tY5wS*NsT>L1%qPQzSvI6)Y!Y4lp8e^w*pqLQ22vhq0IpTdX{LlmMZ zK2+u`W|&pudQUOggevDCG~n_Gx!ZSAYJ%wfoD(YL#_Vk5WgpftH#wZ#-u;!imv zdI%AeQ#hOct1O$p7MsSc|Hvv52ksuTKl75>vBoUNC73%N&UXuek|@ztYpZJ82G%IU z`Qsb5BSs?%3Ua1JMbef?z;Dfg)rdMID$H|uugCY=-A5^5g^SOnt=LcZZ&egzs87%q zuo;pP>cU5r%@0Lq7_w}d)l$qoT&IFS9zF~7^p<8*UjHDPUw0^NyD-qaSNN&_pgex4 zA}ok={)HYerVdNcadyMm80Tp&(>TiJ=I4ayg=uHlEET?a#eh_|GG?RL5{E@*qf&T4 zxmKX81v{phD4j*$>MxG-aJfAqF>d$aA(LGQ7|uEhHTi9m4gUiD^Srk%oW$Cs3P_gk zKq2duWmqai#UG)f-P;qsGVXPmC$*PJ=#$+SMpv0{GxU*Ku@Z%*5FhmwBugnk#Lq__ z2Q`W5u+6nH&PF6&Ad{mQAB%x%U%pB&e|sQD&+H%4gIF{>807dpYfTl~82C zc+UngIgh!D8Giu=zX>1z4fM3R)>t&27dARxDfyDNjtPFPO!o@~FJCtbS@bOK#X17Sw!RVz2((Lo2h3~FGqXCSJI?t)x;SIV7w_w_kl!3DA4t_5wJ(@f1~>P zI`V_g@sus#&N7ey<^t(I+HLp{Q8=u~6}3ok&f8(mVAr$f``Q0%Ag-#!d8de*Dwqo} zEIF2_qO9D9b0-IGjOwE`bX8`XM)_rTjK24wzxql*K1B}2>cfR*NV9GRtDIq0kWvG` z#{2`mX4_KeN*ek7qUv_aI`Y&kAu4T9IYjJVL~5>OX8}m!p&Vm*+#=xb_MnL7AJsUk zJycxr2rz1W{3{i$OlGAE_{`2tUP>|M7U^|mgvuPKW0HU|eN$$$-d`sXp$SLS%QXWB z&IQ)2UrjQk2zAJs-y&}-q8(G&oX(1_3UG9d= z<7L0x7zbcEy>?c<<+zMjDT>^cQ}Lll_~=27h_*<)GbG)hSni||u5VYLAj5Q`Uov&B zMdJ2j`|X6RCRBEs;I#vhjpn<3uS}&A2EaK-F%*-cX^M&=s~T<<1o>1(aT+~s_^l$* z^M0lg-73xHW5k=E#>0tRXsKO<4W-9@$NypLEQ8u=yKo&OxVu}6d(q+!#VPLYTHM{G zK!HMWZ*X^aDekU?6oR{R@_y(1JTv*7$xQZ6_OsS?Uw0jfz~vls_=8axx908Ax2qFT zcDiDl{Ybq7ne!YJA6CNlkO|@P#8&O1&t<_xq={E=ZgouSsD7W&k-jX5uKbWORm<%6 zFMuJ#uNu@^DJjrs@6hns5}~l$aa@$G0>zX!<1%$-rU;;^GL<(@2BWC~Pb&LA8+%f< z6gTYjSCsKE!V82AE|=qTw`DK{(~FB9lv`mutayefRF9OfLuwmg2A$;Y@*;*?dQwoeVL2N!J@2um#(Ll?#am?y0pg1kq75Oo?{y5=` zmnk&#E25D`S>V0eaKn4OO+6#~4&w*s4!aKUbU`c$?1-0{;mF=!jl7@PX-Lrp=E~C^ z6Tw+x)l-w<2cM|UfUiwEx0rA^zP zuE%MZXGyAtpp==&j@!>k-MJQ~0_S~v`SRW(eugN9pdcZi6Za&zU~ywU^il`YlMwRw z-+TlQaPji!_A-O{I-~CsUlVX@k1z68!X9vxMFCbYe!>ZS`W-~l^AOjARCjW??jApK zCs>o#8!L8={tFp7pgiX1+R|H&@3!Ntp(Y5viV2+6!4+};bO3vS!pqq1${_Sr&rDY@ zNk?nE&kh2cl-I!ATT@=x*~lcR1HWp-5+b(wyXG4@<2)*Mgo%0=Sp|b$lAOU~QzzgD z+8q5|jV9#)3qy+5e!HajihkNQFyYChR$ff&3vw4dKt8M)84wkaUS8ULtgavYdh6?B z4>Gmu0D#$Q)_t00FJJL(vp<-^?b$SEW8-`I+OrvwDhg| zcQ%^r>!7eunOBE$J^d7aS(#;TR8|SOwudRF#`SK_?+;yf8DA`qrbESY$PjS-oofy+ zRas~^QZ?OooSWR3cl+v2Aw)`2`0yfI8(YHTbicMc=|WU@o5-vTA)6J^-)+y)wowcF zJ6A^|=dIbMKP&wr@|7-UuG|wSmgF{c@&uEY6>Q^H|AAz1q=MFH13xTfAZ84Q1M~aQ zqGBE!+8z5x@bwRME>{Fv1drT_nehsuYy-QXH6LL1w;aQLII*U2^#q*r>%}!QNHD8R z`5MNG9-ZUF1HbQRLG>7u$9(S(jTsh_#K0W1G|xnDw)}Z`dE$EV<1QB+p(23OVk=JO zJf)<{gNwo`nSbZw$^u;Fa71NwfylHByGiKElWsDaYxhrWzZx1UnJnv=snXARMM5F} z3KQ|myF*V}y8UOC@Nc7Dm91v&-0F)E`D1*h`6@K=$JN_^te2M2?xDa~y9GRe@}Dhg zfUl$SlAMOw0#Q}UL()6pFuy#67Ot;&QrG+pKMdbey)@Wr{E<`^I|6>fOT~^JLE`<0 z0j~v^7Ow+V$i^Hbxlpr>An!Oo&jQeub(FCU4iG@7E8Pl<(gFy-=`3`sF_kWqZy1LjI8JLutme_!uB%E<+^LU^Y1ph zU2{J{lIb=H0E~_5QTGI0bA*^y7b}&PjteMByJ|_zR*NfjLNE*3*Cbd?>MfsHUbAQ- zCS27JOc?1B1uy6X(`iGER_s_CU#GQx3~Q-rW+boKXXwT-^e{ZRjJML6fnB3?D_9!~ zpRDChj=?Ve7;p5;i~2J->^ElyO8r#^>2LkSv}R~2dhLmh^eIN@DQZOj&xABc6^d45 zv=9eI-jN2pvoY17+<~rhD#A7Hr@VV?tB{gr4O7lmZUCd6M@B9>3ax1Anz0Y*=^LSe zzwn294bv*N-b0FOy%LwHVr_t;RP(SS`P5h&{-bzs|KMEwxtby9w0^T3_Fvo)1w?6*DcUMwjW_ zN>_}cRNWkl(%YsnSA2ruc%ZJdlW!UigN05$0!uq`5>hGy$9#}b{&9$~qsa(}9zpl_ zO_=KdALgoZB$Kv}VTVNs<0JRJRfFvpYMkO6I?|h<53fq0E(@_A3hdyZPcfST68-`3 z2WZ9dzun4e^$GFAkUoBz<0Z;&G6qQKy7iVW_EF1D~jjq^N zir<_dWA9J!09<)OaYGve|FF@k?6mbQ-3Sdl0rtvJcZ}1--@}?-qc`;>T;Ie1y<-0q zfrhsq;{^pId04f+L~*o~+it;MNFa^C8X=J#Rl*)(AYbM$?jL;8IPjB4H!UIu7AHf5 zy^0luj>!Pu)+Uch>Lu1l6ACo@x@f=`_Z;}Go7vhkA7OoF&(Yk(6-C%%?Lzp01I(GL zR8wx^0Ib(lB>0SI<1^yqGA)5uA0Q)n@DD&4x415Ld{np)ye9Geqt5`{S6wPKTlv>b zGw=tZpi@v@4H9)$-Xwh&owQP|qDh(q#91%awM$#o-nC$?TRnA{ky=XT2(}aq7fE>B zja4dB!j!JB$~d~tn6`BecBu7(Asv^@BR$wg{g+zamCZDdy0-;<#M@1i zmD##U`#^c$rkD2gisDv=hn9r`g6uy3_9!6a)nHA$OC43%-CNA>D?ym1fkvuqgeF!KDrr`TI8D43 zA@Jgzi!}P}@;e4|7TYR^OUpb+5>?T(rAfti;lyJvp*GzW@W0 zACm7LsPg;$+wA%Kg?U^Ze<1H6$+DZW3G6p(%I7%!QvaNQ13A@Eo4c$NL?X@GS9kg( z89^_XBM<69$11yTZxjLB`}9Fq^gZTI56%aiOUkbARY?~u2SkadUPdXSqf$syeb@Og z!KiI=1XzT@MA-`X7;Xnn-;jKSLD>TsAt*p+8dX?MQrf8RcES2$(x;tdhjiE|=bj#F zQ4H&sAM5+Ct<*BWC`^ZD^qQ4ZpZyT`F+OSAQ|@%S{@c^3?yrW`8IP$kTI+VnL}VkT zoHjkOLoTA&$u8F8OnW2yoPy{?z_RrFvN+4W$qJ{Ixxr6VFNy4jYmf)rh?p3DQhC-l zo6x^#80o;xRD8W2oBk5_@RQeF8>#i@Dr?}BfVB&(Jl%dR#77gUjUlmtkwVfm9=NDi zrKj`g^~p~4tS@drmYjqo$Ja7WAE&Ou$&YGx!&?}!j%sRm37}E1-sN9rNRO{z#}A&< zC|hNL#~)WrK*cno4aqbL_8m`e=S=@jEv={_&&1MwQz;J?l-OdJ=y4~J_7UwH7J2O6 zhQFWtm-QK)uFC_CCr(g}&F4CDnH1_YP6fw^F@D&}b(nC)cZ9_*UJh4__(frjh274h zvPeCs$Y5TxfQDM$Usk#B$hx}BLyiQ_8VE(+&R-e?tomw%VScW7YLE3K0d2XtI@_86 zX@`Hqxj__ARLOxx2`S-BMyuV5iKoZsi_YWcjsfmErmsk-%KdoM(d~XiyPHP zX{h!O8y;K07*LIDfJl>dzt9x!?;G zPM#>m8lYSsap1J#g`|(5*N@ER_{_9s9Fpc_9x&M;AZIcMrYB4P$)fWE*veEL4LE>V z*SQI|E=fpTTsfJDM+;lh;}PT*Ej(b@ckgJt zkJv(K`iCnP>y7d}i2W)>Nr9y5@Xq6_k5YrZMm0h*dzY9%mPII);i3F?a(D1k{0hDW zaj;ar<$?A&2|)v$na6qI_WCxc=@{xkQj9u`&o#Gq!u66;@O&Ua$+#0UyZy=H6SD@4M3nsW^KCwmay>}&w1tJ^Kaz{`eLsk-=SHC?91Aw^iarP@ z=pW{5LCX^nAtB-I{r=^HQesD7z-t@y=G<2HyFFgy^FMuhdU~JU%8NK|wgiXl@C|3X zRrRd;Q6-Ya9w@h~GMUF`+EEl5+yUF*h?_0_6<*LW+5W_?umNI=YL9w`q zql_;AMfI!hAoggi<+J?$W0|e1oGqtp9+mn-0{dIm{7KilRTU4I?3QCV!|fHkg%m+U z`zW;))PJz$H?{TNlerpyXdkE_`0Vj=_PtZn9_oAJhq?mpEla*qw*^<)V+gi>)<7zg zsCN6s9%*AT80R4_e_o43nl~9XSgd6MZGA{err`Rk2%@$nbiX9+WLJo(tLtFh4FRfcq*Lcmh_EJ>4JRCbLc z-dyyyDZksAx$VV|uOPyXd+m>_L7o}hu9kPTK>FCe@Ekpd3414f7qVZt1HBl z%Cg%v<^5c7NZkmvn?zN-kE0_9QRP+JKI%Q~m{wWrA5N)1#5ZgjmCkwc%48TRpJG}O6an*ARj7kl9JU9kQe#|FWrZXFi`X(t)$^DWqaOYw z;}#rnw)TV}tDY1&?bB$6O-v&Nb$gGq2%30vSC>^q)JsSWy763o?$APA1Cu&Y46`|b zkC#3EmRioXr-Hv@fY`Wg&(mQ}8wrEeIL}i&|D9at7_(PK5OAt^;lp#G!zeU+n;?Br zsfK~S_Hg=#!M?ES%O+`K&y&4LQP=20d}hsUUwQ9k1v7R^ex7xNWlK(7A5*F3^!V<%@?x}Dh zS1F}WHS)t(Y-5$3>&l2!DQL?Dki>rRvj(!IXhv=RX-*-yklxvcurKV*2|c_Mb8?AU zF(6NAsqfIC{7N@3Kw+iqJh4B1+-L{R25qvQ<-u(XcK3+$@UkC`s$ym{sQK0F!A@xRC*0exwiQ`-`_LgSIy~7f zRlL>?0zAE$a26RgzJ}@)u6Zu9Kg}o^b(k2hbdx!f93L0&I&n)D@^*F}3?}wIJxnUl zhxEVLxlAu+W^%fkn&3Wj|0Ew16o^3H1XDGJ6;T>eWJZMY%^7xfM#${1kc~feEk8 zfj%t1M~`%1d*6$@O{f(HBl)(D*idhM;?ss{&L@adxNgdY&oqOV-Jb#CXj#ZkjLe%QQW;|OL#GS7sImD`bPD_33VcC>T13`- zv=ju>k9IK#cTSD&9YV}ogGE$|BrGiy`#z7k{) z!;YqXdk-;m!Udto{PtSmntxmuqncNK4bV+(yz)|fw>g>9OEutu22}@a zg7UN1vcG&Ki6CG{%%WUCQM^u=6Sbom45Qor(|z8xYk&t=^p znzGBOHOr9Yp|1WiDxoP9+M3MXNVhX?26Y5kwx59Rrjaw51;;_x3Qx2C@Jpq>hcRLy z_O*y@`s_UVc*W?beEG}Jtw}OiyEPuWe(1G?M9yj@$EQx1a;1Rb4WfPLFs>*Yr-ocF$>48uyalpm3y;pXyBejN;PSYv%QRdkuHZnyabd zYX-Hsg!-SRtGMsmF^^1esGD^!I<>|@GTm11r@*d2X$4CERmDdH8-MqK?AQZsEknxN3 zOPlCDIFL$YpV{~k#mU+E^5P=+f4kIM>!4fhAbh~ZzUbRN;g`OSE8^wLFupxCR)f8L z*i0@cD@m^p{pS3$GKUhLv{1*1H1GwMx3G1^C;ho0*jnBm>U`*E)v7kmwaWgGR&1tF z51Mg#a=oBcK_KDw!8RP|$uGH70%evBD>0r!Fi5kbz5pqy0RbgOZDeI)Uk;d_@nnH@x)LS_}5-FOyUFKFWV8M7S^n z>m-ZV>X`A~@T6GNtv*}a*r%jhkUV7x`N^rL8eP#lAMm^D4^?U8`HL5V24S#=8FyM> zT#drl2M2sVwm;<`%(+n_f?XT#ue=NqawPj;331T5$K^(|&i2WtmXLLaqK_X9v-Vm( zE`1NZ_7z5IEd0JTKfdKKCI$-{T=MaGG3|T!QR_3Q^kq|!{Ip#fmnx^D#3!9O6BfXT z>En&G;@__`Rjw)uwsX!@9VKFGq#S3n<@0k<;0I|pc==AW=<1kW@-Rl_fy*;t%)dftvd-<-dVP~@ zl49EKc&>;Cu=%EH(lvumH|cu5m6!jG*EB8bGdqo9DxUmprOs<0Kx{KR&UNJRt;D#< zIHd-Tv)Ut}+GH!!`x8Hd>DeyNGCZm9W~xxbKNuS*1=04K*UXrQGJ)St6W=-8lj=1q|O%$tOkKC#gxO} zN|aLcTws)J)Rn-*!?pH;Gp$`Gz{cO@Q%YtjZ9g^+sf{(DWK}ajegXH)zjZ1pcU zg#4U?SQO5uAM<(}2cfZVUR&5x=gfuZ_(aA`SJ64jbnqNS8<-C+fv`d{;VEn4C`Wq8 z)>IULc9m#)34YtJXVy4XdDu|?<%sLte(p`GN@%?sHu@CxveJ!xbGm)`A0?U7Gn^qKGA@Uy58 zIs`D&%p`pp0)H1_KVoFMjEtB?z}ZS;iU~&5pSg3BQa~2i0S36eVGX1$xDt{`-g7bv z2rA*;U!AO>&GImq^-3G#?eo`$gZ1=(yNuj)f-jqHBxLu=vUFL(A*0A~`nH^+kpLM3kgr)pq5$G~^^n^pWBo>;r{4jSreEi<;fBWXz~? zS9jh7rX!HEiTmmIIB7YG0i6RjNos2iH2X^APMi5`jl1Rp^00Y;|8#=uY5ZN5=)CMkZyESZF8)vbsW$;WYNpM_0z&rT@ATO&5iBQcnGEcbV=`kQAVAoaR#7& zna;44;GZzuskYhWn9$Raq1tR9qO!t+bT0R`PJhq7ldz?di)L1eu(OWF*Q)?D0T>%g zZ>1%=DIjdVY_0!FYf{|UAJ9=6jGSnWdv!cFy!ZP+Hn)zX^O~32xJn$oANdt}>)04R zK1lBKT^ytOy=*&o7fQ#>7cO~;4>23Y4WfF9v4a*tclHB>iP3e1crsl*YNu&vqZTwy zXyN8!8AV5lAch>fK#sjOGyegGo*|_bw%i*bG)R9H4=Xgr{N|Zw1VRLq!A=#^1Zv*X zv+oV5Yt}6%QmW>is79$xQyv3@NzlGDtL=WCBI$56GQ_=xJP0dJC@}ut`6K1qKoAn( zp(5zEW)B>A1`ga2+5Zhq$zCWx=O7PH%RS$NF4^CJZ!46~=6O%Qf-W%MV5Y1i>R-qHT>1hw2uT^X z#gRirM+o{|ejYOob>&~Buu{n=)r#rBBmItd887#Df{|FIO;wWWMjZwp{JiLzRnnm!sU|5x-w|w?i=_HX5d{<63`HokjqUkfSi7+tvTO?VFR29*O9ScaOOD zjQy`%28qx(DsuRN0H-h3LM&?qMwfiFuKP$!`9nXTiGXlhsnt&ylv0L%QwbB9wL=XE zhF2!v`6BAK9 z2gI7yPjmJ+&8Sxvg+Jm~y|@o-bYY_;<>9WtytuD|GIk-%D&_RMen9s2K>fI7DSXl) z3&zvO1N8lui5ph5(^&@mVm~*34PQovl3@cdf>~8NTm3C*{R^iA7v9S@K)7$>#s(K-Nm^c^_PVm8S>3%KJ#l5nZYGKL@c(}r(hO73q9UA5s&}-28f)$bj~MbXI+ktfxvgLX{6WDWn-T({RLHCSoY`tHX~z(iC4! z1d-x4TL}7P0L-p+=#iq7>wXbRch{cgO_cjPOJ5(urib7Yw=kTFmrsS&t0?W~znYKH z54((^w(K2Sm%2|e^D$-j-+K8PITztuyBp>9w2lm5+KQ(!)joSVo)O1p1Lo@D_>@(u zGSZ*?g}T^xxb}M<(?o-Vo}7aezOi}#H#e15MV_J)oxc0If8JTDD0Y87od+V?y|4=DF zl#?n*Z(G~GKl`;ESDsD^F9NZa`}ANuCpP=IXV{5W<+kh%D!n45YanK}(_X}TkjCYW zK@+hKpAU7(=CR?X0Kqp+WS;3fo{ybcb0^CoqG$VIOAgJCil@OX4=SF z;h{AHIV85qDtYIR7ZFApUJkuXK&DRiNRWNyW6v}g#!b~1`2vxGBiZNv$fGgD8yO59^Srf6Lp!LMJILlorlpZ zf>1ILOLs*1-In~oB*>}L9P_LKn8nljs&*dkXSO@$(y@^yajQ3zMA+5C6W*mRR@|rH zF-20}zw`I3Se19STQcle2&eRS9pY;Z^PG4`pDAzj{qZj=S>zmi4{W-{Od<^E2XEwQ zh(und&Ob@D&+&p8Vj0=MV9aisKW`+=MfIL!XS?%Km)1#@r>b;MIbdrH8joDRzI`3` z>FJcy7c>NJ7u;B+63T4Cvj{eDkr4@HJx9`7*rOm3mq$ZMA6cGgVSLtbZdSx)wmP#c z`h(o0qZg*g;$!(IC&5*dzkRBh%x^scHqiu6gDEafYac9eHUDv_KGSD2@2PEmwm<`Q z6wD%;v@`op`8u*W*xZZVS!=MG<`LqX$6+@T<0q%V9%H2j9u&rNit!>(39|FSU9lB7 z3`oz8-S^*eS?zlpqs<4{G~x<+Swu6nwkU!2kMkVodPqN52$gB0)6+?oZ({z?A6oTn$OOO>1azv!@-Y_ z1Rh1lZ{Ow`Mhor*YF^rs`?sebFc#Aw51k3yDc>Lem$-*g-aXKe$A2LAJ|R^7aq;l* zKpqs>uu3)jN5My1H+S+k(eC!h{h%oxq4jdj*6U+i zURbsK1G)sy*CqB)CZIm|)vkCP#UQ_v1A;)~3dZsf0wi5(bH-qnX!;1GpM6wGx$see z0ENad5}UqoEbdxEMc>JtXWDP-%Lv?kG)Aj?fSeB}L-AreZnpA$Z}+>!_^&uTv-EVu zeDwbEF?_&?@GXu*LDUS5Wdx0oOH$N5PG}JvI1Zbu<9J3!VGL6aB$F#kcgWcY=(UK3 zzfZ-CGx4rur8e+nS|PL&tDl;-R4HxVO20W&3)^E+f+oNLf{ZOJvE#TmHp6yYDwJn~&FcR_fJ2 zBQaXlNv5dv#(sf~(8KxIAr(d8hnOn=Ycv9*Aw-G$pTCBOzXW^6g8__UXB@nbX3|ZQ zcfo8eQ(;@M$rkf_H^y4BMt6frwdP76p3qpy*R{Z-XZUZ@8Np^lp`UPE=Ol>ppDl$v z+K~xagUei-Vo%zX!!W5?oAHs6qNML3=zJJ{=)HFuSd`Wt=A)W0%4%`nf`#p|H*qU_ z*QJEPp>{5R%`%ZJVm>z5l5+DnNBAog@aEl2-x6yw*B&a_zQOJK%(68A3iR}1gfpTcFyjf#%ArZs{OVx{}&uaYX)jTHC zTXDn^_HoK~B#eJVsK{ec{3sTTyVPt(bIlinM#35cUIePcEF6ElcH9>9NY2*vKml*I zx0AfrhV#GH4-cz(uevW)J-00)*XJ3;LHo`x=r3tKSK8eWa1V3dtmZ&Sr3}wWqi^?ekHo%@b7Y2<#&NnY-PTc{5C#<86 zWc`KWp>+Lrs04|q{R8kUZ5}X<`=dWAKaCIjr~Ntjxwm;XMcxFTKN^wPc3s_R&P(P? zyBSb0vTPV$?m@mLOf0lSH8TlYEf4oi3}=d9AT@px)>vv zz-laVFs#@u;EsNBO;_cuY_@jOoO0P&D!T<#t_CQP^yZht@<{}r@G_`)fh1L1eIR)H z!9N?BM1|ur&TcXXSgNjj9*e1jS>$SzGq$%soWo72NM;GHC)RroA}Kv)SSJR~3WD5% z@^XcM`|Z5saQjH#Yw(@eL+UnUvh(hjKt+OfP_1`G8IuC4XDW`WdoGVS&1rL*k_OWA zSFw?@o_D;(X+P0m^h4u2xMR@8LF8AR0)$e+A_7>7`n8iu{9SR!JAe(}B-|FL@BQdC zx>IvK--Te%T>E%Z-|5TZjZ_>qx+`<*KLKA30xR2ozj<)_jl0%WD?4C51*K#I!;OIADp%IrPH(wjc9koGCXdZ+w- zNsNU2-V#2zlFYAZ4u!vmXzgW8zj^PwM;`oSJEt(7;`E0r8L+v47TP@mIfmYX`YfNx z^K4;A2W^3o&PRy+VGdmt`1i&S3~<5E5Ipoxi*!2pDx1zi&P9FOZIdA!+Jhs7c9-4s zGERn8nLoE8wn`#ozdL^a5TwMYlQ7MIZaYqrc`-}O? zR8DnmB3>Oi`i?ib0)txc>Iq4)^)aU%$0nHo$hwDNO1X6A?yUo?z3<&32wYuFZ99z{ ziqJtp(S_`y*sj5!=sH5wD z{8fE^N?)PeydH<0bRTc|hd(fcLzwVyjdH#ULO68NhyxXxIdv!3y;i~5FoH-~XF6^v zGn%676Pm#pqb8~g8ITnXX5VR*51?bAMf(d2L%iE>*`x`e@8Yw{YRM9RzLNwAE9RKh zo#?XuyIYttlb!|a2lR9gh}$q<{bTcDMbu{s4Y| z$=g5plm4(1hIv8%Hkj9I{1O+04NbMaUs7iLcf^V3>>?srZjm8Gm)IA93d6#1qo&Z6 z6BR_0IJlk9oRY1KX^MH}EO?E`xHDjPpV&a zS-R}L9(YZmRNbBdJM!wc=L2n~3kyD!+agP~v`9u>t*6=*dNGfByL``CWy6LUYPY&% z@tlsFs}(yhj5EjljrO!!9=#q!5Il?Qpp3!B0%iyUkU(2SIQ500!a9xbD8QUgG&gHy zvb)XCM{ps zs{2Z*GYjm@RKI(p?ZS`F`Bdt1!2-inB`rh)%U{vo@BaIw6*#Un%s?H5h* z0(iq6=cPf@LOG?21o=9l8}hZRYMn&$_E)_`T?DL+Mq@aZxLlKvMcJkRv!Fp%@a`wP zqOaoJMinOBVR6-*U+#VHz=j_Rwh(alZf*}zm3uX@RNjEyytiFZZ8X`RwqABIRdHPI zZ`J4hykE@3wy;0SIP|ctK>fR&nYVgqoHQX~aa*{5<^-C{HI$VSiyYue>BS>z5F{vM z!+permX{Vi_Dpbt5u~Z1!l2g+lj`+FoWwSUcXowc z&v~yh;ExhFt}{vn$SG-P{FoLD(OJy@{u&TlFtle5Lk~k_1qS;CpV{v^z&c`-+*h;o zG0@*xcT=|GS|@w{G^&iD%Z`bY5W(l}=qJ<8G4-P0^i3dKS%8q6i0Yqi3#~Woo&k22 z5s8E-0Ic#M>R_T%I&cDk;S#xD(q&Cm#@Hdvw}LA3`#pl650kS3C*h}2p_?PX{Sk1a z>rTV$sk~-|uA8;(m(TZJsztGRzA)q!;MGlXf4G$I!>BfezX1TrCU{xc{uzr(x9*R2 z;AV)v9Q@#kdd_gn zweTPs2-SvMUGAf0S}EPIa3BH(x9YUmOhg?w|6~vzYu?}|u0(l$X3Zz>mrhz1QqtZe zQ9bYG6(rfW;ezaPpWY;)#i2|LnyUrcYGjz{*se5%&sGIW<&F8azGe=5X>x0?-$u^N zQ2$96dvKr9Vl*iBOfhb@p{V5lqI(}Thv~(%QT<1{hND)ZIm~mZjHr<-;_msWq!1MT zl?sf^J-M?<@Yuy}qo@b3(T0z0aFCfEn%PKlj{j6^vs`kbzTXj5Qc(!$oIAh0--B5a zXm#EiQGIJAw0i1-JbTS%5hNLRCjI$bjGRr&MWFLT9BthVpeH_Ni)|vFpl8EmZnM0< zVe}*4aHE8V#SMHK*9d6Uz1D4MIHWKMF+@^G#u7rEqqdhAU0e0EX`a3&sZvM>4usJ& z$&X#MHB(eQ^bLz{11vv`OH#sr(uij?$0c;I=?i+Jd=-4T@-yze+!YRog4%RpYt=vA zVrAH8+t8?VzIN{&ru2EzmU;HxNZ}F~yY04`1eTfwNr?ICu(eg2MUY5#PpHrwk~YyY z6#+9~OG9R$0s{U%r;ySIRm6~^;*f6xyGcE_dzBSjC6Dm}>lb7XPR51&2(`0aCCaX4J40jjJ zbw&n*!|NBNls=C;^y~Caei8jZEYbh^m;E0a#K%-yu>Wf1pIjvT(1- zvZ^imq^wrgwH7<1EVyq#9Y-)kQn_~6Dqz)v9-p*6&{Ksyv+R z=kfDi51%2*m!SyO2O~vV&(ggi;s`3gp|yYNA^7iUPvC{Yg!D~;A2S%AsWSnD0(kRm zRn>ymybFR$z~lTJeC*o=wkP4s6=}7b?&VIC*9ifEzZ2DN=&a7L&JcFqht0zBDU5A) z+gmd9QZ$-Tti=JZe}-65a8JUmIm(;i)x9Jzic8YPEdpbqOShr=G{h6C1<}%%PNk`6 zBnuzz&j@q~OfvD5wbKv{M}pf?Z3sM>O$BaUmi$oZBT9cf8l|K275BD3pPpAgu1W}x z1&Db6UX~6usMG6M&JjGzvCd=0AXoXvA*_ANx^z^vxO?>4rA73z=8%FX!5C?=vvd$X z*_27-Uq41HXWF!9rqs$J7zfYriZvT{m=cv%0j z>C_4u8S9|m;*q=_a-7*HU&F$JY|)FE^+K-j-nTKGFSpMEiGprq1Ib12PH9V9V=V8Ud$HNcU zOjmz7Kju`=l6Ut@V{h(&}%wb2}?pjM!2X4jfj|10IaJG=(5e zzFvCZ^|%c}gX^vRM@1FnqkPJ<<0~HQLw%1-P*|>W_VY`j-R6}d61Z{=8N6{HqIsQ6 ze=wBpsNo(d=v)cZay&yOzA_^dlgdw{a#8BbpCKQccc8SF-i1f`M?$oOEZuZ=j-}UP zSV)7EYG%6p*R38Fsri2G`EOfq*NP!`ql{LM6Q1gBH|6S^E}B+VkF_tHZtq8=tw}>+ z6@04?hJrvxV~~utSy9F%3&Znn)pTjxb&cBZ2?F${8ba!(wW7+#S|N_B$hFliX**5x zD6U@UbO@gj$4=wSO9)lDpIHg#Nds+;9f@j*?e=M7p1-1^zoWg!?&CirlAq<5(er4r z4E22v?~AM_XbE3WH`LvW3ageHNhvkZ=g#DUT~5=CMtC@TzC*l!M==>0)1?ra@h=W~ zC6FE_>G=qWDO(5YGA@59F#KrtR-GAKPwR~13wvaspaIs`yUL7LIfF?+^e@dg)e`b` z+>{vq+#85lovS#;TEtW+9%o-X3_NHPD+kFpOJ**M>!KzdNQf_;&zt6x>m}j~t>fIE z)G7?S;?)@S>f`mLxaxe!ZeK`im`})H-AP{G?1p^;0QzALIC>{?e7;6 z7fCM5G8a;Xlc*7R?V0`w@kz}8D*LoEPOn+}F1L>&(meLy)YoXGRMzy9;(n&W*_ioF zJ(k*SZ4f6RvwBmABIo0XS@uHMoh}ibM2CaC^fgl*PGIdI#T7mzaAIsvvDPs1bAyZg zkE~RacJ|=%ON=j0ZUal)*hdYVBGq=Xpz|g-IxxM>`Ay*kPeoD+A;8dtLve1I7|wFY z!^7F7Jh(NzOL(~+nf3AFe3yk`16N5-1t7Fq%0k6^>m@@Nb|rx|bAlOQ2)l5H#Uy`w zRQSsmx*x_17y9&1<_PnM0)^8ko&a8aE2;0PjSx~yPc?KhJ}wvi8*o2&SVl#$AfaLw z)C_xD=KO@l*FHQD|I^{2sojPgpGsuPu4x6uMAcW;Y{3z}87TU8BKeXRc$2r|{J#DU z`+EQtx8=hG*n|WXLAbh58be{B4^141+|;y$>fD^mRQqTF^U>^c1^SvlD(msYQzGHD zJPk{SaxxMwRYPU|vdjnF;L8#Q>kU>R$I0g%HW$dYS z=IeTF&_vU@phs_V=4i+?s^M@&LyIhA7M?*f^_h2iwPal zS8TXVnG%+EVyeR}7AQSBgPpgf)HzRgHw9Eg;O+jy;CFFG>6miMv%5 z7q(@iw%pNDR8G`G+bQE-AG_Ts&ngCA(dF|Xc4FZpQ7hPca~~@_n>E5xJXD!Id-zxX zzxz;j28TGi<}NwLQrpc+7`#sf;?9GsxR6EoK3aG_MTKUtPl%#jmegnSY{CWl z^1IVJ(FDQ?JM5CYQ^W+|1S1HT;l}l$WdP_D)qE4YUezF>g{h)#La*&Ixn#Rx7fj%` z80KGXC^yu$K9=GcOiiMm6^simm*B53(SRdrs1@+iyc5tl7xZ0 z8z_@OINB-ZiqP|!rWhbp2fqb>-5IAgnae=Y@bqvN8f#yNXaJC_te~qxWmv3t%~Sb; zJMPY46|~erB*d(%IpgRp2Jf?=3~?pp?9Rrbpi6z787x{e_%uZ^-G!CJw}!9AnZ4Lq z2PRWS{i|5&E}8+zx)evB6yr!-8$otAVq;m*`qqcwn;*gUtUq&lp@A-&wNM?{l>1FNI7Pr?X4c@*bq3THG3lBS({fn2 zsmKG0zHki%zZSO{a{qHaXWTyOdoJ6EH$OU9XLa?6Y~GcD%ytp0xl~(Mu?`HxRZw5l zPR<3dG&t9L@n@2U?k?f#+w4KG2k}*!;=5Xy=|00#?TJh3jul~Y&TMGc63@C%)x?%q zRHTEh_hrXw=$JpDoDSfaNA2oYN|) z_4Q!LClT;j*JIg4OMqZWgf#Vc5=~fn(s$MhRZG@Akr~qu?VGLTSN{RySN`iig#YG$ z_a9*Rw_AMhuW}btD-|>!bS@OpWDh0+W-8*o)_mV??jX6Ec8UJ{&2KC~73AAN6V%^u z%PC8`GJz*OAM&U=1*&kZ=V2Lv=_%>Cau(E)A&V)OuLU*RDBwj4lX({)`-tIzTf(J? z8rA)9od!oz)otoL^jg6uO~Uh2RpJiktV!}|0uK>ldokvMa1<<0Ho(9as@ixL9?6>&Wd~WfR_8ZuDNy?WP)Na2E+oqGWd0qyBYzTQr81B`A z^ZcwAJFesNJFbcObzH|gI#f7H6D6{Lc(HDi3zGrZepJ*q^y4Ei&6nL)K&$>_OFgNY ztar@7WZiMEwo`-Rk;r9r*(>p8qa=ZQAO#>S3Qb#Xlc`aAN6N0<#o>Z9aWVZ$HYIKX z=VF~8>*PmjpWz+WJQ8FJq?1DGTsW)^??_gIzzveFWzB;b!;{H)nrXO1m4M@Vx8<+17z6_$hWF$tq@=Ryl~9mX#q+Bss$QD zLQSEe3P{ZI$O8+%b$@Tf&BiNOumqqB|3Q-|B2$K?9*lSbb}>kcH)ZH5!Tmb{5mDQo zU4jHfA9$DS;yWEVK%T63@f)oYp>?Bc(f~CaGvb>wT-{lpr^AI^k=(jvrKnmmb)i0= z*J%E+6;uhbn9$Zzw8Ok)U|zJtwTws`?S$kVTfm8qx?r6v-bM2Jt0wXzw0hR-sp)>> zq;P(~&>P<6Ty^1nPLHoNaMvP~?Fk@Mi^^xSpV}T5xaHg0Zq5Y_>tG$MIW+qvw;8M! z+=8I++NB~MvUc%uZCzGaA<5?iWer^S-%|f(PkO5r+^T)H*qjZudzOc}uaPiaPPYq` zOXQ{~5A%U;-quj%bxoT4KA?77_8z<#XEY2%M&75k2lVg6s=EeLhL+atlhIHdZ>kjv zfn~1v%VNF?-1xfXz#_ljA8PY_(vgwq)E???3bTa94Qt zxh6qvE`2{qk8^|Iw)qi5v-7Ghc4d^Kun0E4yv1;@#Rp-f284UHBW!S9A%r}yI@Hwv zWt5|E%6&h!>z2e2+mFL3gD3s7^}UgavV}+qAgMpKnyX&`sdYXFTQ`YeOq*Y3Fq3@Ufu=Fx4i(l zMtZeB%K^h&K}+uLEp~rSH)>P?Xp%ZTQR_hvzzZAd3eDMM*=sRe0zeZky2_t>2E) zc7qDa+1akbl2(iftowOj)a}>>FvDt&6j2(8KM#MtRW9~mr8O0$IhAsW5{zAqzQsC@ z7;;pY7>!SKj+8)%lhJ0ffD2hn1QgJxpzhc4`5f28{5r1V9UTo~Tzf*(Ek^uA0LD+w z;KKyGe52j*V%%jWfC-e6{yzX2lftH5;k7}1(bU%0O4r^M2egu}L6;@wgr@8ZD36b( z0@{WikdR%fCCM#8E{!)y%EK**^mhsxL~;$4uZgWYqt-Zn zf3;}o+B>*45MV)}dcO9qA1~@N?n=^ODrTeQHwKW@27lEcfsrhEbkAA04x^$SJmdmw z2b68Xau*vUU5hS7J&l)q;VRLB{Hh1Nd-!7YY}`(bOtDv!0FBl?s6%`!$nmeBo)jvy zA3ZS&fK)|N^v+0+AUv>aklc}xcYGO$3YwxXS#kz=@kx^$s?>r(pBKwbRE7298Nn^m zR$S^fim0WL&uIn()Hw0$p^3a*Q|Xifnlx(y!hNw~cWK|?wCGaDYIbzHU z7Pl;{=8VwiQ7isMLW%y|6tdn>I<}_DNMMk`b9LTUS3?hm(h*!(Ov;MONd=lnP=6+R zEvA(1@w{pAWVYctQ$2M48I0KV6*Nr8?U_aJ(~rs6qfV!L^RM?lty&BTxd{ysLdbjohHP5*ae4?yBL1GNW(Y{(7|{4S{Sz z#z$`nioSp2*|vgB(0}VWVrY_c1}q5{02Gu*ORT7;cu;G#^%7NDiteZJp+JZbjtO}m z%@Pl`u7G$F?LzwA3Sh07ak1`2KyyWa=2sF36%35gC^*pKkGVJ0(auThLQ7Dz7&Yoc zZK~oR0@4b`UbKi*SE#Zz%}Wz(0WwxeY%r?J<DnJOE$w-Sa{y&S#Vneq1{Hm-^JbzH|g zI^sz;_q>I1o|MZN$O1k;JaW}U?s(Fm!4vXffb6%ZyRnJYG$AO1g?jhZ;h(75v8{ta zEJF_xgrM+kcqd4}IrmO_VAPv{c*u}}F+DY2yEpNsig;L%cS&L9?gdVoWKtFDII8Vc zIA(<7g7onM)IIV|K;AIIY!LI4Cfv(yXaP(-mc|{9CqxM6(w<*DD3sA{ zi#&i*+nb;Pad6I_!Via~^rXVLo^)Ce7VFfxofDuz*ixFkOugNpY!mV>SVxLl!lnU@ z1{ahPqzX_A=$jv6c)dmXaEsHAK11GVC&GPu!%-6`AuEu~6}N|Mfyt*i$-)LPw!nxD z0_=YB8tmJ(7c`!2oGi$2@gtxK%7v*So6uYho`j>pkexfIzwfn;-c>FMnlO^Ij`y+; z;3*<*2JpiPZ$ngt2?znQ9Uz?A9B;vGSu|k}&~9OY!YM`G;@WDWLbBD4OReBHM+|dD zm_~#*XHcyuHzUd}A#VfHF)PG(vh@-)`gKG_yT(;5q;bpxYhmdkBU%0Dsz}m;ZGT<> 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

    y;>mnb4<26^ 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

    51`EQ{;%z**2*~a=X^&-FM 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

    >1wb;6N-3+|E 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

    1=IZtDA#iXt)wfQd49j=k<4AWWdF(b3Z`GoI* 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 literal 0 HcmV?d00001 diff --git a/_freeze/docs/installation/execute-results/html.json b/_freeze/docs/installation/execute-results/html.json index b269b7e..72ee659 100644 --- a/_freeze/docs/installation/execute-results/html.json +++ b/_freeze/docs/installation/execute-results/html.json @@ -1,12 +1,12 @@ -{ - "hash": "65228f7d1a193c5cace2c9a9607b0799", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Installation\nformat:\n html:\n code-fold: false\n---\n\nPyspatialml is available on PyPI and can be installed in the usual manner with:\n\n::: {#bb02f017 .cell execution_count=1}\n``` {.python .cell-code}\npip install Pyspatialml\n```\n:::\n\n\nThe development version, which is more up-to-date with changes to the package\nespecially during these earlier stages of development, can be installed\ndirectly via:\n\n::: {#66ac18c4 .cell execution_count=2}\n``` {.python .cell-code}\npip install git+https://github.com/stevenpawley/Pyspatialml\n```\n:::\n\n\n", - "supporting": [ - "installation_files" - ], - "filters": [], - "includes": {} - } +{ + "hash": "65228f7d1a193c5cace2c9a9607b0799", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Installation\nformat:\n html:\n code-fold: false\n---\n\nPyspatialml is available on PyPI and can be installed in the usual manner with:\n\n::: {#bb02f017 .cell execution_count=1}\n``` {.python .cell-code}\npip install Pyspatialml\n```\n:::\n\n\nThe development version, which is more up-to-date with changes to the package\nespecially during these earlier stages of development, can be installed\ndirectly via:\n\n::: {#66ac18c4 .cell execution_count=2}\n``` {.python .cell-code}\npip install git+https://github.com/stevenpawley/Pyspatialml\n```\n:::\n\n\n", + "supporting": [ + "installation_files" + ], + "filters": [], + "includes": {} + } } \ No newline at end of file diff --git a/_freeze/docs/landcover/execute-results/html.json b/_freeze/docs/landcover/execute-results/html.json index 2840795..ead1c8a 100644 --- a/_freeze/docs/landcover/execute-results/html.json +++ b/_freeze/docs/landcover/execute-results/html.json @@ -1,16 +1,16 @@ -{ - "hash": "c266ff597585baa54084adb9bc9f1dd5", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Landcover classification\nformat:\n html:\n code-fold: false\n---\n\nLandcover classification is a common task in remote sensing. This example\ndemonstrates how to extract training data from a raster and vector data, train\na classifier, and predict landcover classes on a raster.\n\n## Data\n\nThe data used in this example is from the Landsat 7 ETM+ sensor, and represents\nan extract of data derived from the GRASS GIS North Carolina example dataset. \nThe data consists of 6 bands (1, 2, 3, 4, 5, 7) and labelled pixels. The labelled \npixels are used as training data for the classifier. The data is stored in the\n`pyspatialml.datasets` module.\n\n## Extraction Training Data\n\nLoad some training data in the form of polygons, points and labelled pixels in\n``geopandas.GeoDataFrame`` objects. We will also generate some line geometries\nby converting the polygon boundaries into linestrings. All of these geometry\ntypes can be used to spatially query pixel values in a Raster object, however\neach GeoDataFrame must contain only one type of geometry (i.e. either shapely\npoints, polygons or linestrings).\n\n::: {#5384a314 .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\nfrom copy import deepcopy\nimport os\nimport numpy as np\nimport tempfile\nimport geopandas\nimport rasterio.plot\nimport matplotlib.pyplot as plt\n\ntraining_py = geopandas.read_file(nc.polygons)\ntraining_pt = geopandas.read_file(nc.points)\ntraining_px = rasterio.open(nc.labelled_pixels)\ntraining_lines = deepcopy(training_py)\ntraining_lines['geometry'] = training_lines.geometry.boundary\n```\n:::\n\n\nShow training data points and a single raster band using numpy and matplotlib:\n\n::: {#031c229e .cell execution_count=2}\n``` {.python .cell-code}\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\nfig, ax = plt.subplots(figsize=(9, 9))\nstack.lsat7_2000_70.plot(ax=ax)\n\ntraining_py.plot(column=\"label\", ax=ax, legend=True)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-3-output-1.png){width=752 height=694}\n:::\n:::\n\n\nPixel values in the Raster object can be spatially queried using the\n`extract_vector` and `extract_raster` methods. In addition, the\n`extract_xy` method can be used to query pixel values using a 2d array of x\nand y coordinates.\n\nThe `extract_vector` method accepts a Geopandas GeoDataFrame as the\n`gdf` argument. For GeoDataFrames containing shapely point geometries, the\nclosest pixel to each point is sampled. For shapely polygon geometries, all\npixels whose centres are inside the polygon are sampled. For shapely\nlinestring geometries, every pixel touched by the line is sampled. For all\ngeometry types, pixel values are queries for each geometry separately. This\nmeans that overlapping polygons or points that fall within the same pixel with\ncause the same pixel to be sampled multiple times.\n\nBy default, the extract functions return a Geopandas GeoDataFrame of point\ngeometries and the DataFrame containing the extracted pixels, with the column\nnames set by the names of the raster datasets in the Raster object. The user\ncan also use the `return_array=True` argument, which instead of returning a\nDataFrame will return three masked numpy arrays (ids, X, xy) containing the\ngeodataframe index positions, extracted pixel values, and the spatial\ncoordinates of the sampled pixels. These arrays are masked arrays.\n\nThe `extract_raster` method can also be used to spatially query pixel values\nfrom a Raster object using another raster containing labelled pixels. This\nraster has to be spatially aligned with the Raster object. The values of the\nlabelled pixels are returned along with the queried pixel values.\n\n::: {#82546144 .cell execution_count=3}\n``` {.python .cell-code}\n# Extract data from rasters at the training point locations:\ndf_points = stack.extract_vector(training_pt)\ndf_polygons = stack.extract_vector(training_py)\ndf_lines = stack.extract_vector(training_lines)\n```\n:::\n\n\nFor any vector features, a GeoDataFrame is returned containing the extracted\npixel values. A pandas.MultiIndex is used to relate the pixels back to the\noriginal geometries, with the `pixel_idx` index referring to the index of each\npixel, and the `geometry_idx` referring to the index of the original geometry\nin the supplied GeoDataFrame. The pixel values themselves are represented as\n`shapely.geometry.Point` objects. These will need to be joined back with the\ncolumns of the vector features to get the labelled classes. Here we will join\nthe extracted pixels using the \"id\" column and the GeoDataFrame index of the\nvector features:\n\n::: {#b92da33c .cell execution_count=4}\n``` {.python .cell-code}\n# Join the extracted values with other columns from the training data\ndf_points[\"id\"] = training_pt[\"id\"].values\ndf_points = df_points.dropna()\ndf_points.head()\n\ndf_polygons = df_polygons.merge(\n right=training_py.loc[:, [\"label\", \"id\"]], \n left_on=\"geometry_idx\", \n right_on=\"index\",\n right_index=True\n)\n```\n:::\n\n\nIf the training data is from labelled pixels in a raster, then the extracted\ndata will contain a \"value\" column that contains the pixel labels:\n\n::: {#97c015a5 .cell execution_count=5}\n``` {.python .cell-code}\ndf_raster = stack.extract_raster(training_px)\n```\n:::\n\n\n## Model Training\n\nNext we can train a logistic regression classifier:\n\n::: {#efc89d56 .cell execution_count=6}\n``` {.python .cell-code}\nfrom sklearn.linear_model import LogisticRegressionCV\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.model_selection import cross_validate\n\n# define the classifier with standardization of the input features in a\n# pipeline\nlr = Pipeline(\n [('scaling', StandardScaler()),\n ('classifier', LogisticRegressionCV(n_jobs=-1))])\n\n# remove NaNs from training data\ndf_polygons = df_polygons.dropna()\n\n# fit the classifier\nX = df_polygons.drop(columns=[\"id\", \"label\", \"geometry\"]).values\ny = df_polygons[\"id\"].values\nlr.fit(X, y)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```{=html}\n

    \n```\n:::\n:::\n\n\nAfter defining a classifier, a typical step consists of performing a\ncross-validation to evaluate the performance of the model. Scikit-learn\nprovides the cross_validate function for this purpose. In comparison to\nnon-spatial data, spatial data can be spatially correlated, which potentially\ncan mean that geographically proximal samples may not represent truely\nindependent samples if they are within the autocorrelation range of some of the\npredictors. This will lead to overly optimistic performance measures if samples\nin the training dataset / cross-validation partition are strongly spatially\ncorrelated with samples in the test dataset / cross-validation partition.\n\nIn this case, performing cross-validation using groups is useful, because these\ngroups can represent spatial clusters of training samples, and samples from the\nsame group will never occur in both the training and test partitions of a\ncross-validation. Here we can use the polygon indices as the groups, i.e.\npixels within the same polygon will not be split into training and test\npartitions:\n\n::: {#2e5891ba .cell execution_count=7}\n``` {.python .cell-code}\nscores = cross_validate(\n estimator=lr,\n X=X,\n y=y,\n groups=df_polygons.index.droplevel(\"pixel_idx\"),\n scoring=\"accuracy\",\n cv=3,\n n_jobs=1,\n)\nnp.round(scores['test_score'].mean(), 2)\n```\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\n0.75\n```\n:::\n:::\n\n\n## Raster Prediction\n\nPrediction on the Raster object is performed using the `predict` method.\nThe `estimator` is the only required argument. If the `file_path` argument\nis not specified then the result is automatically written to a temporary file.\nThe predict method returns an rasterio.io.DatasetReader object which is open.\n\n::: {#499621f4 .cell execution_count=8}\n``` {.python .cell-code}\n# prediction\nresult = stack.predict(estimator=lr, dtype='int16', nodata=0)\nresult_probs = stack.predict_proba(estimator=lr)\n\n# plot classification result\nresult.iloc[0].cmap = \"Dark2\"\nresult.iloc[0].categorical = True\n\nresult.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-9-output-1.png){width=552 height=427}\n:::\n:::\n\n\nThe `predict_proba` method can be used to output class probabilities as\na multi-band raster (a band for each class probability). In the latter case,\n`indexes` can also be supplied if you only want to output the probabilities\nfor a particular class, or list of classes, by supplying the indices of those\nclasses:\n\n::: {#40b27083 .cell execution_count=9}\n``` {.python .cell-code}\nresult_probs.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/matplotlib/image.py:499: RuntimeWarning: overflow encountered in divide\n A_scaled /= ((a_max - a_min) / frac)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-10-output-2.png){width=602 height=372}\n:::\n:::\n\n\n", - "supporting": [ - "landcover_files" - ], - "filters": [], - "includes": { - "include-in-header": [ - "\n\n\n" - ] - } - } +{ + "hash": "c266ff597585baa54084adb9bc9f1dd5", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Landcover classification\nformat:\n html:\n code-fold: false\n---\n\nLandcover classification is a common task in remote sensing. This example\ndemonstrates how to extract training data from a raster and vector data, train\na classifier, and predict landcover classes on a raster.\n\n## Data\n\nThe data used in this example is from the Landsat 7 ETM+ sensor, and represents\nan extract of data derived from the GRASS GIS North Carolina example dataset. \nThe data consists of 6 bands (1, 2, 3, 4, 5, 7) and labelled pixels. The labelled \npixels are used as training data for the classifier. The data is stored in the\n`pyspatialml.datasets` module.\n\n## Extraction Training Data\n\nLoad some training data in the form of polygons, points and labelled pixels in\n``geopandas.GeoDataFrame`` objects. We will also generate some line geometries\nby converting the polygon boundaries into linestrings. All of these geometry\ntypes can be used to spatially query pixel values in a Raster object, however\neach GeoDataFrame must contain only one type of geometry (i.e. either shapely\npoints, polygons or linestrings).\n\n::: {#5384a314 .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\nfrom copy import deepcopy\nimport os\nimport numpy as np\nimport tempfile\nimport geopandas\nimport rasterio.plot\nimport matplotlib.pyplot as plt\n\ntraining_py = geopandas.read_file(nc.polygons)\ntraining_pt = geopandas.read_file(nc.points)\ntraining_px = rasterio.open(nc.labelled_pixels)\ntraining_lines = deepcopy(training_py)\ntraining_lines['geometry'] = training_lines.geometry.boundary\n```\n:::\n\n\nShow training data points and a single raster band using numpy and matplotlib:\n\n::: {#031c229e .cell execution_count=2}\n``` {.python .cell-code}\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\nfig, ax = plt.subplots(figsize=(9, 9))\nstack.lsat7_2000_70.plot(ax=ax)\n\ntraining_py.plot(column=\"label\", ax=ax, legend=True)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-3-output-1.png){width=752 height=694}\n:::\n:::\n\n\nPixel values in the Raster object can be spatially queried using the\n`extract_vector` and `extract_raster` methods. In addition, the\n`extract_xy` method can be used to query pixel values using a 2d array of x\nand y coordinates.\n\nThe `extract_vector` method accepts a Geopandas GeoDataFrame as the\n`gdf` argument. For GeoDataFrames containing shapely point geometries, the\nclosest pixel to each point is sampled. For shapely polygon geometries, all\npixels whose centres are inside the polygon are sampled. For shapely\nlinestring geometries, every pixel touched by the line is sampled. For all\ngeometry types, pixel values are queries for each geometry separately. This\nmeans that overlapping polygons or points that fall within the same pixel with\ncause the same pixel to be sampled multiple times.\n\nBy default, the extract functions return a Geopandas GeoDataFrame of point\ngeometries and the DataFrame containing the extracted pixels, with the column\nnames set by the names of the raster datasets in the Raster object. The user\ncan also use the `return_array=True` argument, which instead of returning a\nDataFrame will return three masked numpy arrays (ids, X, xy) containing the\ngeodataframe index positions, extracted pixel values, and the spatial\ncoordinates of the sampled pixels. These arrays are masked arrays.\n\nThe `extract_raster` method can also be used to spatially query pixel values\nfrom a Raster object using another raster containing labelled pixels. This\nraster has to be spatially aligned with the Raster object. The values of the\nlabelled pixels are returned along with the queried pixel values.\n\n::: {#82546144 .cell execution_count=3}\n``` {.python .cell-code}\n# Extract data from rasters at the training point locations:\ndf_points = stack.extract_vector(training_pt)\ndf_polygons = stack.extract_vector(training_py)\ndf_lines = stack.extract_vector(training_lines)\n```\n:::\n\n\nFor any vector features, a GeoDataFrame is returned containing the extracted\npixel values. A pandas.MultiIndex is used to relate the pixels back to the\noriginal geometries, with the `pixel_idx` index referring to the index of each\npixel, and the `geometry_idx` referring to the index of the original geometry\nin the supplied GeoDataFrame. The pixel values themselves are represented as\n`shapely.geometry.Point` objects. These will need to be joined back with the\ncolumns of the vector features to get the labelled classes. Here we will join\nthe extracted pixels using the \"id\" column and the GeoDataFrame index of the\nvector features:\n\n::: {#b92da33c .cell execution_count=4}\n``` {.python .cell-code}\n# Join the extracted values with other columns from the training data\ndf_points[\"id\"] = training_pt[\"id\"].values\ndf_points = df_points.dropna()\ndf_points.head()\n\ndf_polygons = df_polygons.merge(\n right=training_py.loc[:, [\"label\", \"id\"]], \n left_on=\"geometry_idx\", \n right_on=\"index\",\n right_index=True\n)\n```\n:::\n\n\nIf the training data is from labelled pixels in a raster, then the extracted\ndata will contain a \"value\" column that contains the pixel labels:\n\n::: {#97c015a5 .cell execution_count=5}\n``` {.python .cell-code}\ndf_raster = stack.extract_raster(training_px)\n```\n:::\n\n\n## Model Training\n\nNext we can train a logistic regression classifier:\n\n::: {#efc89d56 .cell execution_count=6}\n``` {.python .cell-code}\nfrom sklearn.linear_model import LogisticRegressionCV\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.model_selection import cross_validate\n\n# define the classifier with standardization of the input features in a\n# pipeline\nlr = Pipeline(\n [('scaling', StandardScaler()),\n ('classifier', LogisticRegressionCV(n_jobs=-1))])\n\n# remove NaNs from training data\ndf_polygons = df_polygons.dropna()\n\n# fit the classifier\nX = df_polygons.drop(columns=[\"id\", \"label\", \"geometry\"]).values\ny = df_polygons[\"id\"].values\nlr.fit(X, y)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```{=html}\n
    Pipeline(steps=[('scaling', StandardScaler()),\n                ('classifier', LogisticRegressionCV(n_jobs=-1))])
    In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
    On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
    \n```\n:::\n:::\n\n\nAfter defining a classifier, a typical step consists of performing a\ncross-validation to evaluate the performance of the model. Scikit-learn\nprovides the cross_validate function for this purpose. In comparison to\nnon-spatial data, spatial data can be spatially correlated, which potentially\ncan mean that geographically proximal samples may not represent truely\nindependent samples if they are within the autocorrelation range of some of the\npredictors. This will lead to overly optimistic performance measures if samples\nin the training dataset / cross-validation partition are strongly spatially\ncorrelated with samples in the test dataset / cross-validation partition.\n\nIn this case, performing cross-validation using groups is useful, because these\ngroups can represent spatial clusters of training samples, and samples from the\nsame group will never occur in both the training and test partitions of a\ncross-validation. Here we can use the polygon indices as the groups, i.e.\npixels within the same polygon will not be split into training and test\npartitions:\n\n::: {#2e5891ba .cell execution_count=7}\n``` {.python .cell-code}\nscores = cross_validate(\n estimator=lr,\n X=X,\n y=y,\n groups=df_polygons.index.droplevel(\"pixel_idx\"),\n scoring=\"accuracy\",\n cv=3,\n n_jobs=1,\n)\nnp.round(scores['test_score'].mean(), 2)\n```\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\n0.75\n```\n:::\n:::\n\n\n## Raster Prediction\n\nPrediction on the Raster object is performed using the `predict` method.\nThe `estimator` is the only required argument. If the `file_path` argument\nis not specified then the result is automatically written to a temporary file.\nThe predict method returns an rasterio.io.DatasetReader object which is open.\n\n::: {#499621f4 .cell execution_count=8}\n``` {.python .cell-code}\n# prediction\nresult = stack.predict(estimator=lr, dtype='int16', nodata=0)\nresult_probs = stack.predict_proba(estimator=lr)\n\n# plot classification result\nresult.iloc[0].cmap = \"Dark2\"\nresult.iloc[0].categorical = True\n\nresult.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-9-output-1.png){width=552 height=427}\n:::\n:::\n\n\nThe `predict_proba` method can be used to output class probabilities as\na multi-band raster (a band for each class probability). In the latter case,\n`indexes` can also be supplied if you only want to output the probabilities\nfor a particular class, or list of classes, by supplying the indices of those\nclasses:\n\n::: {#40b27083 .cell execution_count=9}\n``` {.python .cell-code}\nresult_probs.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/matplotlib/image.py:499: RuntimeWarning: overflow encountered in divide\n A_scaled /= ((a_max - a_min) / frac)\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](landcover_files/figure-html/cell-10-output-2.png){width=602 height=372}\n:::\n:::\n\n\n", + "supporting": [ + "landcover_files" + ], + "filters": [], + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } + } } \ No newline at end of file diff --git a/_freeze/docs/multitarget-regression-soil-properties/execute-results/html.json b/_freeze/docs/multitarget-regression-soil-properties/execute-results/html.json index 8361b39..dfbb1ee 100644 --- a/_freeze/docs/multitarget-regression-soil-properties/execute-results/html.json +++ b/_freeze/docs/multitarget-regression-soil-properties/execute-results/html.json @@ -1,16 +1,16 @@ -{ - "hash": "308efad333d88256311ff71d4af11322", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Multi-Target Spatial Prediction using the Meuse Dataset\nformat:\n html:\n code-fold: false\n---\n\nHere we are using the meuse dataset which is included in the pyspatialml package as an example of performing a spatial model and prediction. We can access the datasets using the `pyspatialml.datasets` module:\n\n::: {#9f01e6dc .cell execution_count=1}\n``` {.python .cell-code}\nfrom copy import deepcopy\nfrom tempfile import NamedTemporaryFile\nimport geopandas as gpd\nimport numpy as np\nfrom pyspatialml import Raster\nfrom pyspatialml.preprocessing import xy_coordinates, distance_to_corners\nimport pyspatialml.datasets.meuse as ms\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\n```\n:::\n\n\n::: {#745fc2a1 .cell execution_count=2}\n``` {.python .cell-code}\npredictor_files = ms.predictors\ntraining_pts_file = ms.meuse\n```\n:::\n\n\n::: {#099cf2fd .cell execution_count=3}\n``` {.python .cell-code}\nstack = Raster(predictor_files)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\ndict_keys(['chnl_dist', 'dem', 'dist', 'ffreq', 'landimg2', 'landimg3', 'landimg4', 'mrvbf', 'rsp', 'slope', 'soil', 'twi'])\n```\n:::\n:::\n\n\nPyspatialml implements pandas-style indexing for `Raster` objects, using `Raster.loc` to index by the name of the raster, and `Raster.iloc` to select by index. This method also accepts slices. Label-based indexing is also provided directly by the __getattr_ magic method, i.e. `Raster[name]` or for multiple layers `Raster[(names)]`.\n\nFor example we can remove layers from Raster object using the `Raster.drop` method, or by subsetting the raster:\n\n::: {#c1e14c46 .cell execution_count=4}\n``` {.python .cell-code}\nstack.drop('ffreq')\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 11 Layers\n attribute values\n0 names [chnl_dist, dem, dist, landimg2, landimg3, lan...\n1 files [/Users/stevenpawley/GitHub/Pyspatialml/pyspat...\n2 rows 104\n3 cols 78\n4 res (40.0, 40.0)\n5 nodatavals [-99999.0, -99999.0, -1.0, -1.0, -1.0, -1.0, -...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n\n```\n:::\n:::\n\n\nWe can store matplotlib cmaps as an attribute within each layer in the Raster:\n\n::: {#15a7b907 .cell execution_count=5}\n``` {.python .cell-code}\nstack.chnl_dist.cmap = 'RdBu'\nstack.dem.cmap = 'terrain'\nstack.dist.cmap = 'Reds'\nstack.landimg2.cmap = 'Greys'\nstack.landimg3.cmap = 'Greys'\nstack.landimg4.cmap = 'Greys'\nstack.landimg4.cmap = 'Greys'\nstack.mrvbf.cmap = 'jet'\nstack.rsp.cmap = 'gnuplot2'\nstack.slope.cmap = 'PuRd'\nstack.soil.cmap = 'Set2'\nstack.twi.cmap = 'coolwarm'\n```\n:::\n\n\nPlot the predictors in the Raster object as a raster matrix:\n\n::: {#f4a33f49 .cell execution_count=6}\n``` {.python .cell-code}\nmpl.style.use('seaborn-v0_8')\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-7-output-1.png){width=845 height=662}\n:::\n:::\n\n\n## Feature Engineering\n\nWe want the prediction results to be dependent on the spatial locations of the training data. So to include spatial information, coordinate grids can be generated and added to the Raster object:\n\n::: {#e1c12410 .cell execution_count=7}\n``` {.python .cell-code}\nxy_layer = xy_coordinates(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\n```\n:::\n\n\n::: {#009adcf9 .cell execution_count=8}\n``` {.python .cell-code}\nxy_layer = xy_coordinates(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\n\nedms = distance_to_corners(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\nedms.rename(\n {old: new for (old, new) in zip(edms.names, [\"tl\", \"tr\", \"bl\", \"br\", \"c\"])},\n in_place=True\n)\n\nedms.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-9-output-1.png){width=660 height=458}\n:::\n:::\n\n\nAppend them to the Raster object:\n\n::: {#77aa65b8 .cell execution_count=9}\n``` {.python .cell-code}\nstack = stack.append([xy_layer, edms])\n```\n:::\n\n\nPlot the new predictors:\n\n::: {#32cbc2d4 .cell execution_count=10}\n``` {.python .cell-code}\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-11-output-1.png){width=847 height=663}\n:::\n:::\n\n\nThe area that is filled by some of the grids is different. This doesn't matter for the prediction because pixels in the Raster object that include some NaNs in some of the layers will be removed. However, the plots could potentially be given a cleaner look. We can use the Raster.intersect method to fix this:\n\n::: {#76c21e07 .cell execution_count=11}\n``` {.python .cell-code}\nstack = stack.intersect()\n```\n:::\n\n\n::: {#91d55829 .cell execution_count=12}\n``` {.python .cell-code}\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-13-output-1.png){width=847 height=663}\n:::\n:::\n\n\n## Read the Meuse Dataset\n\n::: {#37936033 .cell execution_count=13}\n``` {.python .cell-code}\ntraining_pts = gpd.read_file(training_pts_file)\ntraining_pts.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    cadmiumcopperleadzincelevdistomffreqsoillimelandusedist.mgeometry
    011.785.0299.01022.07.9090.00135813.6111Ah50.0POINT (181072.000 333611.000)
    18.681.0277.01141.06.9830.01222414.0111Ah30.0POINT (181025.000 333558.000)
    26.568.0199.0640.07.8000.10302913.0111Ah150.0POINT (181165.000 333537.000)
    32.681.0116.0257.07.6550.1900948.0120Ga270.0POINT (181298.000 333484.000)
    42.848.0117.0269.07.4800.2770908.7120Ah380.0POINT (181307.000 333330.000)
    \n
    \n```\n:::\n:::\n\n\nPlot the training points:\n\n::: {#4a282046 .cell execution_count=14}\n``` {.python .cell-code}\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\n\nfig, axs = plt.subplots(2, 3, figsize=(8.5, 7))\n\nfor i, (ax, target) in enumerate(zip(axs.ravel(), ['cadmium', 'copper', 'lead', 'zinc', 'om'])):\n ax.set_title(target.title())\n divider = make_axes_locatable(ax)\n cax = divider.append_axes(\"right\", size=\"10%\", pad=0.05)\n training_pts.plot(column=target, legend=True, ax=ax, cax=cax, cmap='viridis')\n \n if i != 0:\n ax.set_yticklabels([])\n \n if i != 3:\n ax.set_xticklabels([])\n else:\n ax.tick_params(axis='x', labelrotation=65)\n \nfig.delaxes(axs.flatten()[i+1])\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-15-output-1.png){width=807 height=641}\n:::\n:::\n\n\n## Extract Raster Values at the Training Point Locations\n\nPixel values from a Raster object can be extracted using geometries within a geopandas.GeoDataFrame (points, lines, polygons) or by using labelled pixels from another raster with the same dimensions and crs.\n\nBy default the extracted values are returned as a geopandas.GeoDataFrame that contains the data and the coordinates of the pixels:\n\n::: {#e95a651d .cell execution_count=15}\n``` {.python .cell-code}\ntraining_df = stack.extract_vector(gdf=training_pts)\n\ntraining_df.index = training_df.index.get_level_values(\"geometry_idx\")\ntraining_df = training_df.merge(\n training_pts.loc[:, (\"lead\", \"cadmium\", \"copper\", \"zinc\", \"om\")], \n left_index=True, \n right_index=True\n) \n```\n:::\n\n\n::: {#2a20967c .cell execution_count=16}\n``` {.python .cell-code}\ntraining_df = training_df.dropna()\ntraining_df.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=16}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    chnl_distdemdistffreqlandimg2landimg3landimg4mrvbfrspslope...trblbrcgeometryleadcadmiumcopperzincom
    geometry_idx
    00.0000003214.00.0013581.097.092.0192.03.523824e-060.0000001.423307...12.369317119.268608100.71743055.470715POINT (181072.000 333611.000)299.011.785.01022.013.6
    179.8498543402.00.0122241.0160.0183.0183.09.879866e-060.0820851.286004...13.928389117.04699798.85848253.235325POINT (181025.000 333558.000)277.08.681.01141.014.0
    20.0000003277.00.1030291.0178.0209.0179.01.340742e-030.0000000.674711...10.295630119.28118198.41239955.226807POINT (181165.000 333537.000)199.06.568.0640.013.0
    3184.7431643563.00.1900941.0114.0135.0152.06.547428e-070.1923251.413479...8.485281120.20815397.18538756.035702POINT (181298.000 333484.000)116.02.681.0257.08.0
    416.7685553406.00.2770901.0133.0154.0151.01.588824e-030.0166890.531276...11.661903117.00427293.19334452.801514POINT (181307.000 333330.000)117.02.848.0269.08.7
    \n

    5 rows × 25 columns

    \n
    \n```\n:::\n:::\n\n\n## Developing a Machine Learning Model\n\nHere we are going to create a machine learning pipeline that correctly handles categorical predictors via one-hot encoding:\n\n::: {#18f93158 .cell execution_count=17}\n``` {.python .cell-code}\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=17}\n```\ndict_keys(['chnl_dist', 'dem', 'dist', 'ffreq', 'landimg2', 'landimg3', 'landimg4', 'mrvbf', 'rsp', 'slope', 'soil', 'twi', 'x_coordinates', 'y_coordinates', 'tl', 'tr', 'bl', 'br', 'c'])\n```\n:::\n:::\n\n\n::: {#3ef2e2ba .cell execution_count=18}\n``` {.python .cell-code}\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import ExtraTreesRegressor\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\n\nsoil_idx = [i for i, name in enumerate(stack.names) if name == 'soil']\n\ntrans = ColumnTransformer([\n ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), soil_idx)\n ], remainder='passthrough')\n\net = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234)\net = Pipeline([\n ('preproc', trans),\n ('regressor', et)])\n```\n:::\n\n\nNow we can separate our response and predictor variables and train the model:\n\n::: {#1761a1ea .cell execution_count=19}\n``` {.python .cell-code}\nX = training_df.loc[:, stack.names]\ny = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']]\net.fit(X, y)\n```\n\n::: {.cell-output .cell-output-display execution_count=19}\n```{=html}\n
    Pipeline(steps=[('preproc',\n                 ColumnTransformer(remainder='passthrough',\n                                   transformers=[('ohe',\n                                                  OneHotEncoder(handle_unknown='ignore'),\n                                                  [10])])),\n                ('regressor',\n                 ExtraTreesRegressor(n_estimators=500, n_jobs=-1,\n                                     random_state=1234))])
    In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
    On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
    \n```\n:::\n:::\n\n\nTo evaluate the performance of the model, we will use 10-fold cross validation:\n\n::: {#92dc1c25 .cell execution_count=20}\n``` {.python .cell-code}\nfrom sklearn.model_selection import cross_validate, KFold\n\nouter = KFold(n_splits=10, shuffle=True, random_state=1234)\nscores = cross_validate(et, X, y, scoring='neg_mean_squared_error', cv=10, n_jobs=1)\nrmse = np.sqrt(-scores['test_score']).mean()\n\nprint(\"Our RMSE score is {}\".format(rmse))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOur RMSE score is 105.19227221271413\n```\n:::\n:::\n\n\n## Feature Importances\n\n::: {#3de44b19 .cell execution_count=21}\n``` {.python .cell-code}\nohe_names = deepcopy(list(stack.names))\nohe_names.insert(soil_idx[0], 'soil1')\nohe_names.insert(soil_idx[0], 'soil2')\nohe_names = np.array(ohe_names)\n```\n:::\n\n\n::: {#dde4cc5c .cell execution_count=22}\n``` {.python .cell-code}\nmpl.style.use('ggplot')\n\nfimp = et.named_steps['regressor'].feature_importances_\n\nfig, ax = plt.subplots(figsize=(4, 6))\nax.barh(y=ohe_names[fimp.argsort()], width=fimp[fimp.argsort()])\nax.set_xlabel('Feature Importance Score')\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-23-output-1.png){width=420 height=504}\n:::\n:::\n\n\n## Prediction on the Raster object\n\n::: {#a177af7f .cell execution_count=23}\n``` {.python .cell-code}\npreds = stack.predict(et)\npreds.rename(\n {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])},\n in_place=True\n)\npreds.lead.cmap = 'rainbow'\npreds.cadmium.cmap = 'rainbow'\npreds.copper.cmap = 'rainbow'\npreds.zinc.cmap = 'rainbow'\npreds.om.cmap = 'rainbow'\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/sklearn/base.py:493: UserWarning: X does not have valid feature names, but OneHotEncoder was fitted with feature names\n warnings.warn(\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/sklearn/base.py:493: UserWarning: X does not have valid feature names, but OneHotEncoder was fitted with feature names\n warnings.warn(\n```\n:::\n:::\n\n\nPlot the results:\n\n::: {#efd9a537 .cell execution_count=24}\n``` {.python .cell-code}\npreds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8))\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-25-output-1.png){width=822 height=634}\n:::\n:::\n\n\n", - "supporting": [ - "multitarget-regression-soil-properties_files/figure-html" - ], - "filters": [], - "includes": { - "include-in-header": [ - "\n\n\n" - ] - } - } +{ + "hash": "308efad333d88256311ff71d4af11322", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Multi-Target Spatial Prediction using the Meuse Dataset\nformat:\n html:\n code-fold: false\n---\n\nHere we are using the meuse dataset which is included in the pyspatialml package as an example of performing a spatial model and prediction. We can access the datasets using the `pyspatialml.datasets` module:\n\n::: {#9f01e6dc .cell execution_count=1}\n``` {.python .cell-code}\nfrom copy import deepcopy\nfrom tempfile import NamedTemporaryFile\nimport geopandas as gpd\nimport numpy as np\nfrom pyspatialml import Raster\nfrom pyspatialml.preprocessing import xy_coordinates, distance_to_corners\nimport pyspatialml.datasets.meuse as ms\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\n```\n:::\n\n\n::: {#745fc2a1 .cell execution_count=2}\n``` {.python .cell-code}\npredictor_files = ms.predictors\ntraining_pts_file = ms.meuse\n```\n:::\n\n\n::: {#099cf2fd .cell execution_count=3}\n``` {.python .cell-code}\nstack = Raster(predictor_files)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\ndict_keys(['chnl_dist', 'dem', 'dist', 'ffreq', 'landimg2', 'landimg3', 'landimg4', 'mrvbf', 'rsp', 'slope', 'soil', 'twi'])\n```\n:::\n:::\n\n\nPyspatialml implements pandas-style indexing for `Raster` objects, using `Raster.loc` to index by the name of the raster, and `Raster.iloc` to select by index. This method also accepts slices. Label-based indexing is also provided directly by the __getattr_ magic method, i.e. `Raster[name]` or for multiple layers `Raster[(names)]`.\n\nFor example we can remove layers from Raster object using the `Raster.drop` method, or by subsetting the raster:\n\n::: {#c1e14c46 .cell execution_count=4}\n``` {.python .cell-code}\nstack.drop('ffreq')\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 11 Layers\n attribute values\n0 names [chnl_dist, dem, dist, landimg2, landimg3, lan...\n1 files [/Users/stevenpawley/GitHub/Pyspatialml/pyspat...\n2 rows 104\n3 cols 78\n4 res (40.0, 40.0)\n5 nodatavals [-99999.0, -99999.0, -1.0, -1.0, -1.0, -1.0, -...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n\n```\n:::\n:::\n\n\nWe can store matplotlib cmaps as an attribute within each layer in the Raster:\n\n::: {#15a7b907 .cell execution_count=5}\n``` {.python .cell-code}\nstack.chnl_dist.cmap = 'RdBu'\nstack.dem.cmap = 'terrain'\nstack.dist.cmap = 'Reds'\nstack.landimg2.cmap = 'Greys'\nstack.landimg3.cmap = 'Greys'\nstack.landimg4.cmap = 'Greys'\nstack.landimg4.cmap = 'Greys'\nstack.mrvbf.cmap = 'jet'\nstack.rsp.cmap = 'gnuplot2'\nstack.slope.cmap = 'PuRd'\nstack.soil.cmap = 'Set2'\nstack.twi.cmap = 'coolwarm'\n```\n:::\n\n\nPlot the predictors in the Raster object as a raster matrix:\n\n::: {#f4a33f49 .cell execution_count=6}\n``` {.python .cell-code}\nmpl.style.use('seaborn-v0_8')\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-7-output-1.png){width=845 height=662}\n:::\n:::\n\n\n## Feature Engineering\n\nWe want the prediction results to be dependent on the spatial locations of the training data. So to include spatial information, coordinate grids can be generated and added to the Raster object:\n\n::: {#e1c12410 .cell execution_count=7}\n``` {.python .cell-code}\nxy_layer = xy_coordinates(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\n```\n:::\n\n\n::: {#009adcf9 .cell execution_count=8}\n``` {.python .cell-code}\nxy_layer = xy_coordinates(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\n\nedms = distance_to_corners(\n layer=stack.iloc[0], \n file_path=NamedTemporaryFile(suffix=\".tif\").name\n)\nedms.rename(\n {old: new for (old, new) in zip(edms.names, [\"tl\", \"tr\", \"bl\", \"br\", \"c\"])},\n in_place=True\n)\n\nedms.plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-9-output-1.png){width=660 height=458}\n:::\n:::\n\n\nAppend them to the Raster object:\n\n::: {#77aa65b8 .cell execution_count=9}\n``` {.python .cell-code}\nstack = stack.append([xy_layer, edms])\n```\n:::\n\n\nPlot the new predictors:\n\n::: {#32cbc2d4 .cell execution_count=10}\n``` {.python .cell-code}\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-11-output-1.png){width=847 height=663}\n:::\n:::\n\n\nThe area that is filled by some of the grids is different. This doesn't matter for the prediction because pixels in the Raster object that include some NaNs in some of the layers will be removed. However, the plots could potentially be given a cleaner look. We can use the Raster.intersect method to fix this:\n\n::: {#76c21e07 .cell execution_count=11}\n``` {.python .cell-code}\nstack = stack.intersect()\n```\n:::\n\n\n::: {#91d55829 .cell execution_count=12}\n``` {.python .cell-code}\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-13-output-1.png){width=847 height=663}\n:::\n:::\n\n\n## Read the Meuse Dataset\n\n::: {#37936033 .cell execution_count=13}\n``` {.python .cell-code}\ntraining_pts = gpd.read_file(training_pts_file)\ntraining_pts.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    cadmiumcopperleadzincelevdistomffreqsoillimelandusedist.mgeometry
    011.785.0299.01022.07.9090.00135813.6111Ah50.0POINT (181072.000 333611.000)
    18.681.0277.01141.06.9830.01222414.0111Ah30.0POINT (181025.000 333558.000)
    26.568.0199.0640.07.8000.10302913.0111Ah150.0POINT (181165.000 333537.000)
    32.681.0116.0257.07.6550.1900948.0120Ga270.0POINT (181298.000 333484.000)
    42.848.0117.0269.07.4800.2770908.7120Ah380.0POINT (181307.000 333330.000)
    \n
    \n```\n:::\n:::\n\n\nPlot the training points:\n\n::: {#4a282046 .cell execution_count=14}\n``` {.python .cell-code}\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\n\nfig, axs = plt.subplots(2, 3, figsize=(8.5, 7))\n\nfor i, (ax, target) in enumerate(zip(axs.ravel(), ['cadmium', 'copper', 'lead', 'zinc', 'om'])):\n ax.set_title(target.title())\n divider = make_axes_locatable(ax)\n cax = divider.append_axes(\"right\", size=\"10%\", pad=0.05)\n training_pts.plot(column=target, legend=True, ax=ax, cax=cax, cmap='viridis')\n \n if i != 0:\n ax.set_yticklabels([])\n \n if i != 3:\n ax.set_xticklabels([])\n else:\n ax.tick_params(axis='x', labelrotation=65)\n \nfig.delaxes(axs.flatten()[i+1])\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-15-output-1.png){width=807 height=641}\n:::\n:::\n\n\n## Extract Raster Values at the Training Point Locations\n\nPixel values from a Raster object can be extracted using geometries within a geopandas.GeoDataFrame (points, lines, polygons) or by using labelled pixels from another raster with the same dimensions and crs.\n\nBy default the extracted values are returned as a geopandas.GeoDataFrame that contains the data and the coordinates of the pixels:\n\n::: {#e95a651d .cell execution_count=15}\n``` {.python .cell-code}\ntraining_df = stack.extract_vector(gdf=training_pts)\n\ntraining_df.index = training_df.index.get_level_values(\"geometry_idx\")\ntraining_df = training_df.merge(\n training_pts.loc[:, (\"lead\", \"cadmium\", \"copper\", \"zinc\", \"om\")], \n left_index=True, \n right_index=True\n) \n```\n:::\n\n\n::: {#2a20967c .cell execution_count=16}\n``` {.python .cell-code}\ntraining_df = training_df.dropna()\ntraining_df.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=16}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    chnl_distdemdistffreqlandimg2landimg3landimg4mrvbfrspslope...trblbrcgeometryleadcadmiumcopperzincom
    geometry_idx
    00.0000003214.00.0013581.097.092.0192.03.523824e-060.0000001.423307...12.369317119.268608100.71743055.470715POINT (181072.000 333611.000)299.011.785.01022.013.6
    179.8498543402.00.0122241.0160.0183.0183.09.879866e-060.0820851.286004...13.928389117.04699798.85848253.235325POINT (181025.000 333558.000)277.08.681.01141.014.0
    20.0000003277.00.1030291.0178.0209.0179.01.340742e-030.0000000.674711...10.295630119.28118198.41239955.226807POINT (181165.000 333537.000)199.06.568.0640.013.0
    3184.7431643563.00.1900941.0114.0135.0152.06.547428e-070.1923251.413479...8.485281120.20815397.18538756.035702POINT (181298.000 333484.000)116.02.681.0257.08.0
    416.7685553406.00.2770901.0133.0154.0151.01.588824e-030.0166890.531276...11.661903117.00427293.19334452.801514POINT (181307.000 333330.000)117.02.848.0269.08.7
    \n

    5 rows × 25 columns

    \n
    \n```\n:::\n:::\n\n\n## Developing a Machine Learning Model\n\nHere we are going to create a machine learning pipeline that correctly handles categorical predictors via one-hot encoding:\n\n::: {#18f93158 .cell execution_count=17}\n``` {.python .cell-code}\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=17}\n```\ndict_keys(['chnl_dist', 'dem', 'dist', 'ffreq', 'landimg2', 'landimg3', 'landimg4', 'mrvbf', 'rsp', 'slope', 'soil', 'twi', 'x_coordinates', 'y_coordinates', 'tl', 'tr', 'bl', 'br', 'c'])\n```\n:::\n:::\n\n\n::: {#3ef2e2ba .cell execution_count=18}\n``` {.python .cell-code}\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import ExtraTreesRegressor\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\n\nsoil_idx = [i for i, name in enumerate(stack.names) if name == 'soil']\n\ntrans = ColumnTransformer([\n ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), soil_idx)\n ], remainder='passthrough')\n\net = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234)\net = Pipeline([\n ('preproc', trans),\n ('regressor', et)])\n```\n:::\n\n\nNow we can separate our response and predictor variables and train the model:\n\n::: {#1761a1ea .cell execution_count=19}\n``` {.python .cell-code}\nX = training_df.loc[:, stack.names]\ny = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']]\net.fit(X, y)\n```\n\n::: {.cell-output .cell-output-display execution_count=19}\n```{=html}\n
    Pipeline(steps=[('preproc',\n                 ColumnTransformer(remainder='passthrough',\n                                   transformers=[('ohe',\n                                                  OneHotEncoder(handle_unknown='ignore'),\n                                                  [10])])),\n                ('regressor',\n                 ExtraTreesRegressor(n_estimators=500, n_jobs=-1,\n                                     random_state=1234))])
    In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
    On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
    \n```\n:::\n:::\n\n\nTo evaluate the performance of the model, we will use 10-fold cross validation:\n\n::: {#92dc1c25 .cell execution_count=20}\n``` {.python .cell-code}\nfrom sklearn.model_selection import cross_validate, KFold\n\nouter = KFold(n_splits=10, shuffle=True, random_state=1234)\nscores = cross_validate(et, X, y, scoring='neg_mean_squared_error', cv=10, n_jobs=1)\nrmse = np.sqrt(-scores['test_score']).mean()\n\nprint(\"Our RMSE score is {}\".format(rmse))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOur RMSE score is 105.19227221271413\n```\n:::\n:::\n\n\n## Feature Importances\n\n::: {#3de44b19 .cell execution_count=21}\n``` {.python .cell-code}\nohe_names = deepcopy(list(stack.names))\nohe_names.insert(soil_idx[0], 'soil1')\nohe_names.insert(soil_idx[0], 'soil2')\nohe_names = np.array(ohe_names)\n```\n:::\n\n\n::: {#dde4cc5c .cell execution_count=22}\n``` {.python .cell-code}\nmpl.style.use('ggplot')\n\nfimp = et.named_steps['regressor'].feature_importances_\n\nfig, ax = plt.subplots(figsize=(4, 6))\nax.barh(y=ohe_names[fimp.argsort()], width=fimp[fimp.argsort()])\nax.set_xlabel('Feature Importance Score')\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-23-output-1.png){width=420 height=504}\n:::\n:::\n\n\n## Prediction on the Raster object\n\n::: {#a177af7f .cell execution_count=23}\n``` {.python .cell-code}\npreds = stack.predict(et)\npreds.rename(\n {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])},\n in_place=True\n)\npreds.lead.cmap = 'rainbow'\npreds.cadmium.cmap = 'rainbow'\npreds.copper.cmap = 'rainbow'\npreds.zinc.cmap = 'rainbow'\npreds.om.cmap = 'rainbow'\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/sklearn/base.py:493: UserWarning: X does not have valid feature names, but OneHotEncoder was fitted with feature names\n warnings.warn(\n/Users/stevenpawley/Library/Caches/pypoetry/virtualenvs/pyspatialml-NqZ1tMUm-py3.11/lib/python3.11/site-packages/sklearn/base.py:493: UserWarning: X does not have valid feature names, but OneHotEncoder was fitted with feature names\n warnings.warn(\n```\n:::\n:::\n\n\nPlot the results:\n\n::: {#efd9a537 .cell execution_count=24}\n``` {.python .cell-code}\npreds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8))\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](multitarget-regression-soil-properties_files/figure-html/cell-25-output-1.png){width=822 height=634}\n:::\n:::\n\n\n", + "supporting": [ + "multitarget-regression-soil-properties_files/figure-html" + ], + "filters": [], + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } + } } \ No newline at end of file diff --git a/_freeze/docs/plotting/execute-results/html.json b/_freeze/docs/plotting/execute-results/html.json index 88499cb..223f175 100644 --- a/_freeze/docs/plotting/execute-results/html.json +++ b/_freeze/docs/plotting/execute-results/html.json @@ -1,12 +1,12 @@ -{ - "hash": "3ef826464cf0375a69bc32e5b2fd457c", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Plotting\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nBoth `Raster` and `RasterLayer` objects include basic plotting methods. The\nplot method for a `RasterLayer` object produces a single raster plot using the\n`matplotlib.pyplot.imshow` method.\n\nFor convenience, plot settings such as color ramps and stretches can also be\nset for each RasterLayer using the `RasterLayer.cmap` that support matplotlib\ncmap's, and the `RasterLayer.norm` attribute to associate a\n`matplotlib.colors.Normalize` stretch with each RasterLayer:\n\nTo plot a single RasterLayer:\n\n::: {#06613099 .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\nimport matplotlib.pyplot as plt\n\nstack = Raster([nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7])\n\n# set RasterLayer color table\nstack.lsat7_2000_10.cmap = \"plasma\"\n\n# plot a single layer using an existing axis\nfig, ax = plt.subplots()\nstack.lsat7_2000_10.plot(ax=ax)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](plotting_files/figure-html/cell-2-output-1.png){width=499 height=413}\n:::\n:::\n\n\nFor RasterLayers that represent categorical data types, e.g. land cover, then\nthe `RasterLayer.categorical=True` attribute will cause the cmap to be\nconverted to a discrete scale.\n\nThe default plot method for a `Raster` object produces a raster-matrix plot of\nthe individual RasterLayers. By default this plot preserves the plotting\nattributes of the individual rasters:\n\nPlot all RasterLayers in a Raster object:\n\n::: {#ee72d541 .cell execution_count=2}\n``` {.python .cell-code}\nstack.lsat7_2000_10.cmap = \"Blues\"\nstack.lsat7_2000_20.cmap = \"Greens\"\nstack.lsat7_2000_30.cmap = \"Reds\"\nstack.lsat7_2000_40.cmap = \"RdPu\"\nstack.lsat7_2000_50.cmap = \"autumn\"\nstack.lsat7_2000_70.cmap = \"hot\"\n\nstack.plot(\n title_fontsize=8,\n label_fontsize=6,\n legend_fontsize=6,\n names=[\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"],\n fig_kwds={\"figsize\": (8, 4)},\n subplots_kwds={\"wspace\": 0.3}\n)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](plotting_files/figure-html/cell-3-output-1.png){width=679 height=342}\n:::\n:::\n\n\nThe `Raster.plot` method also provides `cmap` and `norm` arguments that can be\nused to override the settings of the individual RasterLayers. Additional\nsettings can be passed to control plot layout using the `figure_kwds`,\n`legend_kwds` and `subplots_kwds` arguments.\n\n", - "supporting": [ - "plotting_files" - ], - "filters": [], - "includes": {} - } +{ + "hash": "3ef826464cf0375a69bc32e5b2fd457c", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Plotting\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nBoth `Raster` and `RasterLayer` objects include basic plotting methods. The\nplot method for a `RasterLayer` object produces a single raster plot using the\n`matplotlib.pyplot.imshow` method.\n\nFor convenience, plot settings such as color ramps and stretches can also be\nset for each RasterLayer using the `RasterLayer.cmap` that support matplotlib\ncmap's, and the `RasterLayer.norm` attribute to associate a\n`matplotlib.colors.Normalize` stretch with each RasterLayer:\n\nTo plot a single RasterLayer:\n\n::: {#06613099 .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nfrom pyspatialml.datasets import nc\nimport matplotlib.pyplot as plt\n\nstack = Raster([nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7])\n\n# set RasterLayer color table\nstack.lsat7_2000_10.cmap = \"plasma\"\n\n# plot a single layer using an existing axis\nfig, ax = plt.subplots()\nstack.lsat7_2000_10.plot(ax=ax)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](plotting_files/figure-html/cell-2-output-1.png){width=499 height=413}\n:::\n:::\n\n\nFor RasterLayers that represent categorical data types, e.g. land cover, then\nthe `RasterLayer.categorical=True` attribute will cause the cmap to be\nconverted to a discrete scale.\n\nThe default plot method for a `Raster` object produces a raster-matrix plot of\nthe individual RasterLayers. By default this plot preserves the plotting\nattributes of the individual rasters:\n\nPlot all RasterLayers in a Raster object:\n\n::: {#ee72d541 .cell execution_count=2}\n``` {.python .cell-code}\nstack.lsat7_2000_10.cmap = \"Blues\"\nstack.lsat7_2000_20.cmap = \"Greens\"\nstack.lsat7_2000_30.cmap = \"Reds\"\nstack.lsat7_2000_40.cmap = \"RdPu\"\nstack.lsat7_2000_50.cmap = \"autumn\"\nstack.lsat7_2000_70.cmap = \"hot\"\n\nstack.plot(\n title_fontsize=8,\n label_fontsize=6,\n legend_fontsize=6,\n names=[\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"],\n fig_kwds={\"figsize\": (8, 4)},\n subplots_kwds={\"wspace\": 0.3}\n)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](plotting_files/figure-html/cell-3-output-1.png){width=679 height=342}\n:::\n:::\n\n\nThe `Raster.plot` method also provides `cmap` and `norm` arguments that can be\nused to override the settings of the individual RasterLayers. Additional\nsettings can be passed to control plot layout using the `figure_kwds`,\n`legend_kwds` and `subplots_kwds` arguments.\n\n", + "supporting": [ + "plotting_files" + ], + "filters": [], + "includes": {} + } } \ No newline at end of file diff --git a/_freeze/docs/quickstart/execute-results/html.json b/_freeze/docs/quickstart/execute-results/html.json index 7c2fd54..029269b 100644 --- a/_freeze/docs/quickstart/execute-results/html.json +++ b/_freeze/docs/quickstart/execute-results/html.json @@ -1,16 +1,16 @@ -{ - "hash": "1ddec99dd2cca1a0e802081725fd4c4e", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Quick start\nformat:\n html:\n code-fold: false\n toc: true\n---\n\n## Initiating a Raster Object\n\nWe are going to use a set of Landsat 7 bands contained within the nc example\ndata:\n\n::: {#4cb5727a .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.nc as nc\nimport matplotlib.pyplot as plt\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\n```\n:::\n\n\nThese raster datasets are aligned in terms of their extent and coordinate\nreference systems. We can 'stack' these into a Raster class so that we can\nperform machine learning related operations on the set of rasters:\n\n::: {#22e619cd .cell execution_count=2}\n``` {.python .cell-code}\nstack = Raster(predictors)\n```\n:::\n\n\nWhen a Raster object is created, the names to each layer are automatically\ncreated based on syntactically-correct versions of the file basenames:\n\n::: {#df26959e .cell execution_count=3}\n``` {.python .cell-code}\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70'])\n```\n:::\n:::\n\n\nColor ramps and matplotlib.colors.Normalize objects can be assigned to each\nRasterLayer in the object using the `cmap` and `norm` attributes for\nconvenient in plotting:\n\n::: {#1cd341e5 .cell execution_count=4}\n``` {.python .cell-code}\nstack.lsat7_2000_10.cmap = \"Blues\"\nstack.lsat7_2000_20.cmap = \"Greens\"\nstack.lsat7_2000_30.cmap = \"Reds\"\nstack.lsat7_2000_40.cmap = \"RdPu\"\nstack.lsat7_2000_50.cmap = \"autumn\"\nstack.lsat7_2000_70.cmap = \"hot\"\n\nstack.plot(\n title_fontsize=8,\n label_fontsize=6,\n legend_fontsize=6,\n names=[\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"],\n fig_kwds={\"figsize\": (8, 4)},\n subplots_kwds={\"wspace\": 0.3}\n)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](quickstart_files/figure-html/cell-5-output-1.png){width=679 height=342}\n:::\n:::\n\n\n## Subsetting and Indexing\n\nIndexing of Raster objects is provided by several methods:\n\nThe ``Raster[keys]`` method enables key-based indexing using a name of a\nRasterLayer, or a list of names. Direct subsetting of a Raster object instance\nreturns a RasterLayer if only a single label is used, otherwise it always\nreturns a new Raster object containing only the selected layers.\n\nThe ``Raster.iloc[int, list, tuple, slice]`` method allows a Raster object\ninstance to be subset using integer-based indexing or slicing. The ``iloc``\nmethod returns a RasterLayer object if only a single index is used, otherwise\nit always returns a new Raster object containing only the selected layers.\n\nSubsetting of a Raster object instance can also occur by using attribute names\nin the form of ``Raster.name_of_layer``. Because only a single RasterLayer can\nbe subset at one time using this approach, a RasterLayer object is always\nreturned.\n\nExamples of methods to subset a Raster object:\n\n::: {#fdbfb00a .cell execution_count=5}\n``` {.python .cell-code}\n# subset based on position\nsingle_layer = stack.iloc[0]\n\n# subset using a slice\nnew_raster_obj = stack.iloc[0:3]\n\n# subset using labels\nsingle_layer = stack['lsat7_2000_10']\nsingle_layer = stack.lsat7_2000_10\n\n# list or tuple of keys\nnew_raster_obj = stack[('lsat7_2000_10', 'lsat7_2000_20')]\n```\n:::\n\n\nIterate through RasterLayers individually:\n\n::: {#d38cee29 .cell execution_count=6}\n``` {.python .cell-code}\nfor name, layer in stack.items():\n print(name, layer)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nlsat7_2000_10 \nlsat7_2000_20 \nlsat7_2000_30 \nlsat7_2000_40 \nlsat7_2000_50 \nlsat7_2000_70 \n```\n:::\n:::\n\n\nReplace a RasterLayer with another:\n\n::: {#a66d0bd5 .cell execution_count=7}\n``` {.python .cell-code}\nstack.iloc[0] = Raster(nc.band7).iloc[0]\n\nstack.iloc[0].plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](quickstart_files/figure-html/cell-8-output-1.png){width=499 height=413}\n:::\n:::\n\n\n## Appending and Dropping Layers\n\nAppend layers from another Raster to the stack. Duplicate names are\nautomatically given a suffix.\n\n::: {#9d580c66 .cell execution_count=8}\n``` {.python .cell-code}\nstack.append(Raster(nc.band7), in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_1', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\nRename RasterLayers using a dict of old_name : new_name pairs:\n\n::: {#35b931db .cell execution_count=9}\n``` {.python .cell-code}\nstack.names\nstack.rename({'lsat7_2000_30': 'new_name'}, in_place=True)\nstack.names\nstack.new_name\nstack['new_name']\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\n\n```\n:::\n:::\n\n\nDrop a RasterLayer:\n\n::: {#7517a32e .cell execution_count=10}\n``` {.python .cell-code}\nstack.names\nstack.drop(labels='lsat7_2000_70_1', in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'new_name', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\n## Integration with Pandas\n\nData from a Raster object can converted into a `Pandas.DataDrame`, with each\npixel representing by a row, and columns reflecting the x, y coordinates and\nthe values of each RasterLayer in the Raster object:\n\n::: {#62ad6b48 .cell execution_count=11}\n``` {.python .cell-code}\nimport pandas as pd\n\ndf = stack.to_pandas(max_pixels=50000, resampling='nearest')\ndf.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    xylsat7_2000_10lsat7_2000_20new_namelsat7_2000_40lsat7_2000_50lsat7_2000_70_2
    0630534.000000228114.0NaNNaNNaNNaNNaNNaN
    1630562.558402228114.0NaNNaNNaNNaNNaNNaN
    2630591.116803228114.0NaNNaNNaNNaNNaNNaN
    3630619.675205228114.0NaNNaNNaNNaNNaNNaN
    4630648.233607228114.0NaNNaNNaNNaNNaNNaN
    \n
    \n```\n:::\n:::\n\n\nThe original raster is up-sampled based on max_pixels and the resampling\nmethod, which uses all of resampling methods available in the underlying\nrasterio library for decimated reads.\n\n## Saving a Raster to File\n\nSave a Raster:\n\n::: {#a5671c9d .cell execution_count=12}\n``` {.python .cell-code}\nimport tempfile\n\ntmp_tif = tempfile.NamedTemporaryFile().name + '.tif'\nnewstack = stack.write(file_path=tmp_tif, nodata=-9999)\nnewstack.new_name.read()\nnewstack = None\n```\n:::\n\n\n", - "supporting": [ - "quickstart_files" - ], - "filters": [], - "includes": { - "include-in-header": [ - "\n\n\n" - ] - } - } +{ + "hash": "1ddec99dd2cca1a0e802081725fd4c4e", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Quick start\nformat:\n html:\n code-fold: false\n toc: true\n---\n\n## Initiating a Raster Object\n\nWe are going to use a set of Landsat 7 bands contained within the nc example\ndata:\n\n::: {#4cb5727a .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.nc as nc\nimport matplotlib.pyplot as plt\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\n```\n:::\n\n\nThese raster datasets are aligned in terms of their extent and coordinate\nreference systems. We can 'stack' these into a Raster class so that we can\nperform machine learning related operations on the set of rasters:\n\n::: {#22e619cd .cell execution_count=2}\n``` {.python .cell-code}\nstack = Raster(predictors)\n```\n:::\n\n\nWhen a Raster object is created, the names to each layer are automatically\ncreated based on syntactically-correct versions of the file basenames:\n\n::: {#df26959e .cell execution_count=3}\n``` {.python .cell-code}\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70'])\n```\n:::\n:::\n\n\nColor ramps and matplotlib.colors.Normalize objects can be assigned to each\nRasterLayer in the object using the `cmap` and `norm` attributes for\nconvenient in plotting:\n\n::: {#1cd341e5 .cell execution_count=4}\n``` {.python .cell-code}\nstack.lsat7_2000_10.cmap = \"Blues\"\nstack.lsat7_2000_20.cmap = \"Greens\"\nstack.lsat7_2000_30.cmap = \"Reds\"\nstack.lsat7_2000_40.cmap = \"RdPu\"\nstack.lsat7_2000_50.cmap = \"autumn\"\nstack.lsat7_2000_70.cmap = \"hot\"\n\nstack.plot(\n title_fontsize=8,\n label_fontsize=6,\n legend_fontsize=6,\n names=[\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"],\n fig_kwds={\"figsize\": (8, 4)},\n subplots_kwds={\"wspace\": 0.3}\n)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](quickstart_files/figure-html/cell-5-output-1.png){width=679 height=342}\n:::\n:::\n\n\n## Subsetting and Indexing\n\nIndexing of Raster objects is provided by several methods:\n\nThe ``Raster[keys]`` method enables key-based indexing using a name of a\nRasterLayer, or a list of names. Direct subsetting of a Raster object instance\nreturns a RasterLayer if only a single label is used, otherwise it always\nreturns a new Raster object containing only the selected layers.\n\nThe ``Raster.iloc[int, list, tuple, slice]`` method allows a Raster object\ninstance to be subset using integer-based indexing or slicing. The ``iloc``\nmethod returns a RasterLayer object if only a single index is used, otherwise\nit always returns a new Raster object containing only the selected layers.\n\nSubsetting of a Raster object instance can also occur by using attribute names\nin the form of ``Raster.name_of_layer``. Because only a single RasterLayer can\nbe subset at one time using this approach, a RasterLayer object is always\nreturned.\n\nExamples of methods to subset a Raster object:\n\n::: {#fdbfb00a .cell execution_count=5}\n``` {.python .cell-code}\n# subset based on position\nsingle_layer = stack.iloc[0]\n\n# subset using a slice\nnew_raster_obj = stack.iloc[0:3]\n\n# subset using labels\nsingle_layer = stack['lsat7_2000_10']\nsingle_layer = stack.lsat7_2000_10\n\n# list or tuple of keys\nnew_raster_obj = stack[('lsat7_2000_10', 'lsat7_2000_20')]\n```\n:::\n\n\nIterate through RasterLayers individually:\n\n::: {#d38cee29 .cell execution_count=6}\n``` {.python .cell-code}\nfor name, layer in stack.items():\n print(name, layer)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nlsat7_2000_10 \nlsat7_2000_20 \nlsat7_2000_30 \nlsat7_2000_40 \nlsat7_2000_50 \nlsat7_2000_70 \n```\n:::\n:::\n\n\nReplace a RasterLayer with another:\n\n::: {#a66d0bd5 .cell execution_count=7}\n``` {.python .cell-code}\nstack.iloc[0] = Raster(nc.band7).iloc[0]\n\nstack.iloc[0].plot()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](quickstart_files/figure-html/cell-8-output-1.png){width=499 height=413}\n:::\n:::\n\n\n## Appending and Dropping Layers\n\nAppend layers from another Raster to the stack. Duplicate names are\nautomatically given a suffix.\n\n::: {#9d580c66 .cell execution_count=8}\n``` {.python .cell-code}\nstack.append(Raster(nc.band7), in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'lsat7_2000_30', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_1', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\nRename RasterLayers using a dict of old_name : new_name pairs:\n\n::: {#35b931db .cell execution_count=9}\n``` {.python .cell-code}\nstack.names\nstack.rename({'lsat7_2000_30': 'new_name'}, in_place=True)\nstack.names\nstack.new_name\nstack['new_name']\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\n\n```\n:::\n:::\n\n\nDrop a RasterLayer:\n\n::: {#7517a32e .cell execution_count=10}\n``` {.python .cell-code}\nstack.names\nstack.drop(labels='lsat7_2000_70_1', in_place=True)\nstack.names\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\ndict_keys(['lsat7_2000_10', 'lsat7_2000_20', 'new_name', 'lsat7_2000_40', 'lsat7_2000_50', 'lsat7_2000_70_2'])\n```\n:::\n:::\n\n\n## Integration with Pandas\n\nData from a Raster object can converted into a `Pandas.DataDrame`, with each\npixel representing by a row, and columns reflecting the x, y coordinates and\nthe values of each RasterLayer in the Raster object:\n\n::: {#62ad6b48 .cell execution_count=11}\n``` {.python .cell-code}\nimport pandas as pd\n\ndf = stack.to_pandas(max_pixels=50000, resampling='nearest')\ndf.head()\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    xylsat7_2000_10lsat7_2000_20new_namelsat7_2000_40lsat7_2000_50lsat7_2000_70_2
    0630534.000000228114.0NaNNaNNaNNaNNaNNaN
    1630562.558402228114.0NaNNaNNaNNaNNaNNaN
    2630591.116803228114.0NaNNaNNaNNaNNaNNaN
    3630619.675205228114.0NaNNaNNaNNaNNaNNaN
    4630648.233607228114.0NaNNaNNaNNaNNaNNaN
    \n
    \n```\n:::\n:::\n\n\nThe original raster is up-sampled based on max_pixels and the resampling\nmethod, which uses all of resampling methods available in the underlying\nrasterio library for decimated reads.\n\n## Saving a Raster to File\n\nSave a Raster:\n\n::: {#a5671c9d .cell execution_count=12}\n``` {.python .cell-code}\nimport tempfile\n\ntmp_tif = tempfile.NamedTemporaryFile().name + '.tif'\nnewstack = stack.write(file_path=tmp_tif, nodata=-9999)\nnewstack.new_name.read()\nnewstack = None\n```\n:::\n\n\n", + "supporting": [ + "quickstart_files" + ], + "filters": [], + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } + } } \ No newline at end of file diff --git a/_freeze/docs/sampling/execute-results/html.json b/_freeze/docs/sampling/execute-results/html.json index 4a2a5e8..9b6ba1e 100644 --- a/_freeze/docs/sampling/execute-results/html.json +++ b/_freeze/docs/sampling/execute-results/html.json @@ -1,16 +1,16 @@ -{ - "hash": "f4b98349d93d08e9877aa37589816d4f", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Random Sampling\nformat:\n html:\n code-fold: false\n toc: true\n---\n\n## Random Uniform Sampling\n\nFor many spatial models, it is common to take a random sample of the\npredictors to represent a single class (i.e. an environmental background or\npseudo-absences in a binary classification model). The sample function is\nsupplied in the sampling module for this purpose:\n\n::: {#a3807ffc .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.nc as nc\nimport matplotlib.pyplot as plt\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\n# extract training data using a random sample\ndf_rand = stack.sample(size=1000, random_state=1)\ndf_rand.plot()\n```\n\n::: {.cell-output .cell-output-display}\n![](sampling_files/figure-html/cell-2-output-1.png){width=480 height=411}\n:::\n:::\n\n\n## Stratified Random Sampling\n\nThe sample function also enables stratified random sampling based on passing a\ncategorical raster dataset to the strata argument. The categorical raster\nshould spatially overlap with the dataset to be sampled, but it does not need\nto be of the same grid resolution. This raster should be passed as a opened\nrasterio dataset:\n\n::: {#0245d53c .cell execution_count=2}\n``` {.python .cell-code}\nstrata = Raster(nc.strata)\ndf_strata = stack.sample(size=5, strata=strata, random_state=1)\ndf_strata = df_strata.dropna()\ndf_strata\n```\n\n::: {.cell-output .cell-output-display execution_count=2}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    lsat7_2000_10lsat7_2000_20lsat7_2000_30lsat7_2000_40lsat7_2000_50lsat7_2000_70geometry
    096.078.088.049.071.063.0POINT (641093.250 225135.750)
    1113.0103.0122.066.0136.0110.0POINT (640979.250 222342.750)
    382.066.067.064.076.052.0POINT (640095.750 225848.250)
    499.088.095.056.098.078.0POINT (637559.250 226788.750)
    581.069.076.073.0118.072.0POINT (635621.250 218324.250)
    1091.078.081.077.097.073.0POINT (634709.250 221943.750)
    1172.061.051.0104.091.047.0POINT (639269.250 220005.750)
    1286.075.078.073.087.060.0POINT (639326.250 224964.750)
    1371.053.048.059.078.046.0POINT (635222.250 218951.250)
    1576.059.063.065.0114.064.0POINT (633027.750 218580.750)
    1775.061.055.070.074.043.0POINT (633369.750 219435.750)
    1878.066.069.069.0110.072.0POINT (633198.750 225506.250)
    1968.052.040.079.058.030.0POINT (637986.750 222998.250)
    2070.055.052.062.079.047.0POINT (635649.750 217440.750)
    2271.053.048.064.077.042.0POINT (635564.250 222713.250)
    2372.053.051.058.082.051.0POINT (633056.250 218324.250)
    2681.078.079.034.041.028.0POINT (639297.750 223625.250)
    2773.057.051.016.014.010.0POINT (635364.750 224736.750)
    2873.057.052.055.057.040.0POINT (635535.750 223311.750)
    30138.0120.0132.065.0129.0126.0POINT (634196.250 226190.250)
    3172.060.047.069.082.046.0POINT (639810.750 219749.250)
    32132.0122.0140.073.0171.0176.0POINT (640352.250 218238.750)
    33170.0157.0176.080.0182.0183.0POINT (639924.750 219692.250)
    34115.098.0106.060.0110.0102.0POINT (639953.250 219578.250)
    \n
    \n```\n:::\n:::\n\n\n", - "supporting": [ - "sampling_files" - ], - "filters": [], - "includes": { - "include-in-header": [ - "\n\n\n" - ] - } - } +{ + "hash": "f4b98349d93d08e9877aa37589816d4f", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Random Sampling\nformat:\n html:\n code-fold: false\n toc: true\n---\n\n## Random Uniform Sampling\n\nFor many spatial models, it is common to take a random sample of the\npredictors to represent a single class (i.e. an environmental background or\npseudo-absences in a binary classification model). The sample function is\nsupplied in the sampling module for this purpose:\n\n::: {#a3807ffc .cell execution_count=1}\n``` {.python .cell-code}\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.nc as nc\nimport matplotlib.pyplot as plt\n\npredictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]\nstack = Raster(predictors)\n\n# extract training data using a random sample\ndf_rand = stack.sample(size=1000, random_state=1)\ndf_rand.plot()\n```\n\n::: {.cell-output .cell-output-display}\n![](sampling_files/figure-html/cell-2-output-1.png){width=480 height=411}\n:::\n:::\n\n\n## Stratified Random Sampling\n\nThe sample function also enables stratified random sampling based on passing a\ncategorical raster dataset to the strata argument. The categorical raster\nshould spatially overlap with the dataset to be sampled, but it does not need\nto be of the same grid resolution. This raster should be passed as a opened\nrasterio dataset:\n\n::: {#0245d53c .cell execution_count=2}\n``` {.python .cell-code}\nstrata = Raster(nc.strata)\ndf_strata = stack.sample(size=5, strata=strata, random_state=1)\ndf_strata = df_strata.dropna()\ndf_strata\n```\n\n::: {.cell-output .cell-output-display execution_count=2}\n```{=html}\n
    \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    lsat7_2000_10lsat7_2000_20lsat7_2000_30lsat7_2000_40lsat7_2000_50lsat7_2000_70geometry
    096.078.088.049.071.063.0POINT (641093.250 225135.750)
    1113.0103.0122.066.0136.0110.0POINT (640979.250 222342.750)
    382.066.067.064.076.052.0POINT (640095.750 225848.250)
    499.088.095.056.098.078.0POINT (637559.250 226788.750)
    581.069.076.073.0118.072.0POINT (635621.250 218324.250)
    1091.078.081.077.097.073.0POINT (634709.250 221943.750)
    1172.061.051.0104.091.047.0POINT (639269.250 220005.750)
    1286.075.078.073.087.060.0POINT (639326.250 224964.750)
    1371.053.048.059.078.046.0POINT (635222.250 218951.250)
    1576.059.063.065.0114.064.0POINT (633027.750 218580.750)
    1775.061.055.070.074.043.0POINT (633369.750 219435.750)
    1878.066.069.069.0110.072.0POINT (633198.750 225506.250)
    1968.052.040.079.058.030.0POINT (637986.750 222998.250)
    2070.055.052.062.079.047.0POINT (635649.750 217440.750)
    2271.053.048.064.077.042.0POINT (635564.250 222713.250)
    2372.053.051.058.082.051.0POINT (633056.250 218324.250)
    2681.078.079.034.041.028.0POINT (639297.750 223625.250)
    2773.057.051.016.014.010.0POINT (635364.750 224736.750)
    2873.057.052.055.057.040.0POINT (635535.750 223311.750)
    30138.0120.0132.065.0129.0126.0POINT (634196.250 226190.250)
    3172.060.047.069.082.046.0POINT (639810.750 219749.250)
    32132.0122.0140.073.0171.0176.0POINT (640352.250 218238.750)
    33170.0157.0176.080.0182.0183.0POINT (639924.750 219692.250)
    34115.098.0106.060.0110.0102.0POINT (639953.250 219578.250)
    \n
    \n```\n:::\n:::\n\n\n", + "supporting": [ + "sampling_files" + ], + "filters": [], + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } + } } \ No newline at end of file diff --git a/_freeze/docs/spatial-features/execute-results/html.json b/_freeze/docs/spatial-features/execute-results/html.json index fee68bf..2e97717 100644 --- a/_freeze/docs/spatial-features/execute-results/html.json +++ b/_freeze/docs/spatial-features/execute-results/html.json @@ -1,12 +1,12 @@ -{ - "hash": "fb14d013abd3b63ee2a6abfe3f924f31", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Incorporating Spatial Autocorrelation into Spatial Predictions\nformat:\n html:\n code-fold: false\n---\n\nSimilarly to example 1, we are using the meuse dataset again to perform a multi-target prediction of soil properties using a regression model. However, in this case we will attempt to account for spatial autocorrelation in the model directly by generating new features that are based on the distance-weighted means of surrounding spatial locations.\n\n::: {#0bcf6e26 .cell execution_count=1}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport numpy as np\nfrom tempfile import NamedTemporaryFile\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.meuse as ms\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n```\n:::\n\n\n## Preparing the Raster Predictors\n\nImport the raster predictors from the `pyspatialml.datasets.meuse` module:\n\n::: {#ebe6123b .cell execution_count=2}\n``` {.python .cell-code}\npredictor_files = ms.predictors\ntraining_pts_file = ms.meuse\nstack = Raster(predictor_files)\nstack.drop('ffreq')\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 11 Layers\n attribute values\n0 names [chnl_dist, dem, dist, landimg2, landimg3, lan...\n1 files [/Users/stevenpawley/GitHub/Pyspatialml/pyspat...\n2 rows 104\n3 cols 78\n4 res (40.0, 40.0)\n5 nodatavals [-99999.0, -99999.0, -1.0, -1.0, -1.0, -1.0, -...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=2}\n```\n\n```\n:::\n:::\n\n\nIn order to generate new features from surrounding spatial locations, we need their x,y coordinates, which will will add to the stack of the raster predictors using the `pyspatialml.preprocessing.xy_coordinates` function:\n\n::: {#0393e2ac .cell execution_count=3}\n``` {.python .cell-code}\nfrom pyspatialml.preprocessing import xy_coordinates\n\nxy_layers = xy_coordinates(stack.iloc[0], NamedTemporaryFile(suffix=\".tif\").name)\nstack = stack.append(xy_layers, in_place=False)\n```\n:::\n\n\nQuickly plot the raster predictors:\n\n::: {#cba259ea .cell execution_count=4}\n``` {.python .cell-code}\nmpl.style.use('seaborn-v0_8')\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](spatial-features_files/figure-html/cell-5-output-1.png){width=817 height=663}\n:::\n:::\n\n\n## Extract the Training Data\n\nSpatially query the raster predictors at the training point locations:\n\n::: {#06d01eb2 .cell execution_count=5}\n``` {.python .cell-code}\ntraining_pts = gpd.read_file(training_pts_file)\ntraining_df = stack.extract_vector(gdf=training_pts)\n\ntraining_df.index = training_df.index.get_level_values(\"geometry_idx\")\ntraining_df = training_df.merge(\n training_pts.loc[:, (\"lead\", \"cadmium\", \"copper\", \"zinc\", \"om\")], \n left_index=True, \n right_index=True\n) \ntraining_df = training_df.dropna()\n```\n:::\n\n\nSplit the response/target variables from the predictors:\n\n::: {#3138a3c4 .cell execution_count=6}\n``` {.python .cell-code}\nX = training_df.loc[:, stack.names].values\ny = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']].values\n```\n:::\n\n\n## Develop a Spatially-Lagged Machine Learning Model\n\nAs well as using the ExtraTreeRegressor model which was also used in example 1, here we will use the custom `pyspatialml.estimators.SpatialLagRegressor` metalearner class to wrap the extratrees regressor into a model that adds a new feature based on the distance-weighted mean of spatially-proximal observations:\n\n::: {#e50ffc54 .cell execution_count=7}\n``` {.python .cell-code}\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import ExtraTreesRegressor\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\nfrom pyspatialml.transformers import KNNTransformer\nfrom sklearn.model_selection import cross_validate, KFold\nfrom sklearn.model_selection import GridSearchCV\n\n# define regressor\net = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234)\n\nsoil_index = list(stack.names).index(\"soil\")\nxy_indexes = [list(stack.names).index(i) for i in [\"x_coordinates\", \"y_coordinates\"]]\n\npreproc = ColumnTransformer([\n ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), [soil_index]),\n ('lags', KNNTransformer(weights='distance', measure=\"mean\"), xy_indexes)\n], remainder='passthrough')\n\nwflow = Pipeline([\n ('preproc', preproc),\n ('regressor', et)\n])\n\nsearch_grid = {\"preproc__lags__n_neighbors\": [3, 5, 7, 9]}\ninner = KFold(n_splits=3, shuffle=True, random_state=1234)\nmodel = GridSearchCV(wflow, param_grid=search_grid, cv=inner, scoring=\"r2\")\n```\n:::\n\n\nFit the model and cross-validate:\n\n::: {#5d0230a7 .cell execution_count=8}\n``` {.python .cell-code}\nmodel = model.fit(X, y)\nmodel.best_params_\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n{'preproc__lags__n_neighbors': 9}\n```\n:::\n:::\n\n\n::: {#4a619dd2 .cell execution_count=9}\n``` {.python .cell-code}\nouter = KFold(n_splits=10, shuffle=True, random_state=1234)\n\nscores = cross_validate(model, X, y, scoring='neg_mean_squared_error', cv=outer, n_jobs=1)\nrmse = np.sqrt(-scores['test_score']).mean()\n\nprint(\"Our RMSE score is {}\".format(rmse))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOur RMSE score is 102.27495341202624\n```\n:::\n:::\n\n\nComparing the RMSE score the the score obtained in example 1, where the spatial structure of the training data was accounted for indirectly by added a variety of raster distance measures, we can see that the RMSE score is slightly improved.\n\n## Multi-Target Predictions\n\n::: {#ddc87c2a .cell execution_count=10}\n``` {.python .cell-code}\npreds = stack.predict(model)\npreds.rename(\n {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])},\n in_place=True\n)\npreds.lead.cmap = 'rainbow'\npreds.cadmium.cmap = 'rainbow'\npreds.copper.cmap = 'rainbow'\npreds.zinc.cmap = 'rainbow'\npreds.om.cmap = 'rainbow'\n```\n:::\n\n\n::: {#911ae7fb .cell execution_count=11}\n``` {.python .cell-code}\npreds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8))\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](spatial-features_files/figure-html/cell-12-output-1.png){width=822 height=634}\n:::\n:::\n\n\n", - "supporting": [ - "spatial-features_files" - ], - "filters": [], - "includes": {} - } +{ + "hash": "fb14d013abd3b63ee2a6abfe3f924f31", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Incorporating Spatial Autocorrelation into Spatial Predictions\nformat:\n html:\n code-fold: false\n---\n\nSimilarly to example 1, we are using the meuse dataset again to perform a multi-target prediction of soil properties using a regression model. However, in this case we will attempt to account for spatial autocorrelation in the model directly by generating new features that are based on the distance-weighted means of surrounding spatial locations.\n\n::: {#0bcf6e26 .cell execution_count=1}\n``` {.python .cell-code}\nimport geopandas as gpd\nimport numpy as np\nfrom tempfile import NamedTemporaryFile\nfrom pyspatialml import Raster\nimport pyspatialml.datasets.meuse as ms\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n```\n:::\n\n\n## Preparing the Raster Predictors\n\nImport the raster predictors from the `pyspatialml.datasets.meuse` module:\n\n::: {#ebe6123b .cell execution_count=2}\n``` {.python .cell-code}\npredictor_files = ms.predictors\ntraining_pts_file = ms.meuse\nstack = Raster(predictor_files)\nstack.drop('ffreq')\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nRaster Object Containing 11 Layers\n attribute values\n0 names [chnl_dist, dem, dist, landimg2, landimg3, lan...\n1 files [/Users/stevenpawley/GitHub/Pyspatialml/pyspat...\n2 rows 104\n3 cols 78\n4 res (40.0, 40.0)\n5 nodatavals [-99999.0, -99999.0, -1.0, -1.0, -1.0, -1.0, -...\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=2}\n```\n\n```\n:::\n:::\n\n\nIn order to generate new features from surrounding spatial locations, we need their x,y coordinates, which will will add to the stack of the raster predictors using the `pyspatialml.preprocessing.xy_coordinates` function:\n\n::: {#0393e2ac .cell execution_count=3}\n``` {.python .cell-code}\nfrom pyspatialml.preprocessing import xy_coordinates\n\nxy_layers = xy_coordinates(stack.iloc[0], NamedTemporaryFile(suffix=\".tif\").name)\nstack = stack.append(xy_layers, in_place=False)\n```\n:::\n\n\nQuickly plot the raster predictors:\n\n::: {#cba259ea .cell execution_count=4}\n``` {.python .cell-code}\nmpl.style.use('seaborn-v0_8')\naxs = stack.plot(figsize=(9, 7))\nax = axs.flatten()[10]\nim = ax.images\nim[0].colorbar.set_ticks([1,2,3])\nax = axs.flatten()[8]\nax.tick_params(axis='x', labelrotation=65)\n\nplt.tight_layout()\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](spatial-features_files/figure-html/cell-5-output-1.png){width=817 height=663}\n:::\n:::\n\n\n## Extract the Training Data\n\nSpatially query the raster predictors at the training point locations:\n\n::: {#06d01eb2 .cell execution_count=5}\n``` {.python .cell-code}\ntraining_pts = gpd.read_file(training_pts_file)\ntraining_df = stack.extract_vector(gdf=training_pts)\n\ntraining_df.index = training_df.index.get_level_values(\"geometry_idx\")\ntraining_df = training_df.merge(\n training_pts.loc[:, (\"lead\", \"cadmium\", \"copper\", \"zinc\", \"om\")], \n left_index=True, \n right_index=True\n) \ntraining_df = training_df.dropna()\n```\n:::\n\n\nSplit the response/target variables from the predictors:\n\n::: {#3138a3c4 .cell execution_count=6}\n``` {.python .cell-code}\nX = training_df.loc[:, stack.names].values\ny = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']].values\n```\n:::\n\n\n## Develop a Spatially-Lagged Machine Learning Model\n\nAs well as using the ExtraTreeRegressor model which was also used in example 1, here we will use the custom `pyspatialml.estimators.SpatialLagRegressor` metalearner class to wrap the extratrees regressor into a model that adds a new feature based on the distance-weighted mean of spatially-proximal observations:\n\n::: {#e50ffc54 .cell execution_count=7}\n``` {.python .cell-code}\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import ExtraTreesRegressor\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\nfrom pyspatialml.transformers import KNNTransformer\nfrom sklearn.model_selection import cross_validate, KFold\nfrom sklearn.model_selection import GridSearchCV\n\n# define regressor\net = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234)\n\nsoil_index = list(stack.names).index(\"soil\")\nxy_indexes = [list(stack.names).index(i) for i in [\"x_coordinates\", \"y_coordinates\"]]\n\npreproc = ColumnTransformer([\n ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), [soil_index]),\n ('lags', KNNTransformer(weights='distance', measure=\"mean\"), xy_indexes)\n], remainder='passthrough')\n\nwflow = Pipeline([\n ('preproc', preproc),\n ('regressor', et)\n])\n\nsearch_grid = {\"preproc__lags__n_neighbors\": [3, 5, 7, 9]}\ninner = KFold(n_splits=3, shuffle=True, random_state=1234)\nmodel = GridSearchCV(wflow, param_grid=search_grid, cv=inner, scoring=\"r2\")\n```\n:::\n\n\nFit the model and cross-validate:\n\n::: {#5d0230a7 .cell execution_count=8}\n``` {.python .cell-code}\nmodel = model.fit(X, y)\nmodel.best_params_\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n{'preproc__lags__n_neighbors': 9}\n```\n:::\n:::\n\n\n::: {#4a619dd2 .cell execution_count=9}\n``` {.python .cell-code}\nouter = KFold(n_splits=10, shuffle=True, random_state=1234)\n\nscores = cross_validate(model, X, y, scoring='neg_mean_squared_error', cv=outer, n_jobs=1)\nrmse = np.sqrt(-scores['test_score']).mean()\n\nprint(\"Our RMSE score is {}\".format(rmse))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nOur RMSE score is 102.27495341202624\n```\n:::\n:::\n\n\nComparing the RMSE score the the score obtained in example 1, where the spatial structure of the training data was accounted for indirectly by added a variety of raster distance measures, we can see that the RMSE score is slightly improved.\n\n## Multi-Target Predictions\n\n::: {#ddc87c2a .cell execution_count=10}\n``` {.python .cell-code}\npreds = stack.predict(model)\npreds.rename(\n {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])},\n in_place=True\n)\npreds.lead.cmap = 'rainbow'\npreds.cadmium.cmap = 'rainbow'\npreds.copper.cmap = 'rainbow'\npreds.zinc.cmap = 'rainbow'\npreds.om.cmap = 'rainbow'\n```\n:::\n\n\n::: {#911ae7fb .cell execution_count=11}\n``` {.python .cell-code}\npreds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8))\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](spatial-features_files/figure-html/cell-12-output-1.png){width=822 height=634}\n:::\n:::\n\n\n", + "supporting": [ + "spatial-features_files" + ], + "filters": [], + "includes": {} + } } \ No newline at end of file diff --git a/_freeze/docs/transformers/execute-results/html.json b/_freeze/docs/transformers/execute-results/html.json index be08a23..7558378 100644 --- a/_freeze/docs/transformers/execute-results/html.json +++ b/_freeze/docs/transformers/execute-results/html.json @@ -1,12 +1,12 @@ -{ - "hash": "f438721f18ba534a03eaea64365fd148", - "result": { - "engine": "jupyter", - "markdown": "---\ntitle: Transformers\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nThe transformers module contains classes that are used for spatial feature engineering.\n\n## Spatial Lag Transformer\n\nA transformer to create spatial lag variables by using a\nweighted mean/mode of the values of the K-neighboring observations. The\nweighted mean/mode of the surrounding observations are appended as a new\nfeature to the right-most column in the training data. The `measure` parameter\nshould be set to 'mode' for classification, and 'mean' for regression.\n\n```\nKNNTransformer(\n n_neighbors=7,\n weights=\"distance\",\n measure=\"mean\",\n radius=1.0,\n algorithm=\"auto\",\n leaf_size=30,\n metric=\"minkowski\",\n p=2,\n normalize=True,\n metric_params=None,\n kernel_params=None,\n n_jobs=1\n)\n```\n\n## GeoDistTransformer\n\nA common spatial feature engineering task is to create new features that\ndescribe the proximity to some reference locations. The GeoDistTransformer\ncan be used to add these features as part of a machine learning pipeline.\n\n```\nGeoDistTransformer(refs, log=False)\n```\n\nWhere `refs` are an array of coordinates of reference locations in\n(m, n-dimensional) order, such as\n{n_locations, x_coordinates, y_coordinates, ...} for as many dimensions as\nrequired. For example to calculate distances to a single x,y,z location:\n\n```\nrefs = [-57.345, -110.134, 1012]\n```\n\nAnd to calculate distances to three x,y reference locations:\n\n```\nrefs = [\n [-57.345, -110.134],\n [-56.345, -109.123],\n [-58.534, -112.123]\n]\n```\n\nThe supplied array has to have at least x,y coordinates with a\n(1, 2) shape for a single location.\n\n", - "supporting": [ - "transformers_files" - ], - "filters": [], - "includes": {} - } +{ + "hash": "f438721f18ba534a03eaea64365fd148", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: Transformers\nformat:\n html:\n code-fold: false\n toc: true\n---\n\nThe transformers module contains classes that are used for spatial feature engineering.\n\n## Spatial Lag Transformer\n\nA transformer to create spatial lag variables by using a\nweighted mean/mode of the values of the K-neighboring observations. The\nweighted mean/mode of the surrounding observations are appended as a new\nfeature to the right-most column in the training data. The `measure` parameter\nshould be set to 'mode' for classification, and 'mean' for regression.\n\n```\nKNNTransformer(\n n_neighbors=7,\n weights=\"distance\",\n measure=\"mean\",\n radius=1.0,\n algorithm=\"auto\",\n leaf_size=30,\n metric=\"minkowski\",\n p=2,\n normalize=True,\n metric_params=None,\n kernel_params=None,\n n_jobs=1\n)\n```\n\n## GeoDistTransformer\n\nA common spatial feature engineering task is to create new features that\ndescribe the proximity to some reference locations. The GeoDistTransformer\ncan be used to add these features as part of a machine learning pipeline.\n\n```\nGeoDistTransformer(refs, log=False)\n```\n\nWhere `refs` are an array of coordinates of reference locations in\n(m, n-dimensional) order, such as\n{n_locations, x_coordinates, y_coordinates, ...} for as many dimensions as\nrequired. For example to calculate distances to a single x,y,z location:\n\n```\nrefs = [-57.345, -110.134, 1012]\n```\n\nAnd to calculate distances to three x,y reference locations:\n\n```\nrefs = [\n [-57.345, -110.134],\n [-56.345, -109.123],\n [-58.534, -112.123]\n]\n```\n\nThe supplied array has to have at least x,y coordinates with a\n(1, 2) shape for a single location.\n\n", + "supporting": [ + "transformers_files" + ], + "filters": [], + "includes": {} + } } \ No newline at end of file diff --git a/_freeze/site_libs/clipboard/clipboard.min.js b/_freeze/site_libs/clipboard/clipboard.min.js index 1103f81..9f97edb 100644 --- a/_freeze/site_libs/clipboard/clipboard.min.js +++ b/_freeze/site_libs/clipboard/clipboard.min.js @@ -1,7 +1,7 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1 - - - + + + + diff --git a/docs/quickstart.qmd b/docs/guide.qmd similarity index 96% rename from docs/quickstart.qmd rename to docs/guide.qmd index ebaa814..e8e2b1d 100644 --- a/docs/quickstart.qmd +++ b/docs/guide.qmd @@ -1,169 +1,169 @@ ---- -title: "Quick start" -format: - html: - code-fold: false - toc: true -jupyter: python3 ---- - -## Initiating a Raster Object - -We are going to use a set of Landsat 7 bands contained within the nc example -data: - -```{python} -from pyspatialml import Raster -import pyspatialml.datasets.nc as nc -import matplotlib.pyplot as plt - -predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] -``` - -These raster datasets are aligned in terms of their extent and coordinate -reference systems. We can 'stack' these into a Raster class so that we can -perform machine learning related operations on the set of rasters: - -```{python} -stack = Raster(predictors) -``` - -When a Raster object is created, the names to each layer are automatically -created based on syntactically-correct versions of the file basenames: - -```{python} -stack.names -``` - -Color ramps and matplotlib.colors.Normalize objects can be assigned to each -RasterLayer in the object using the `cmap` and `norm` attributes for -convenient in plotting: - -```{python} -stack.lsat7_2000_10.cmap = "Blues" -stack.lsat7_2000_20.cmap = "Greens" -stack.lsat7_2000_30.cmap = "Reds" -stack.lsat7_2000_40.cmap = "RdPu" -stack.lsat7_2000_50.cmap = "autumn" -stack.lsat7_2000_70.cmap = "hot" - -stack.plot( - title_fontsize=8, - label_fontsize=6, - legend_fontsize=6, - names=["B1", "B2", "B3", "B4", "B5", "B7"], - fig_kwds={"figsize": (8, 4)}, - subplots_kwds={"wspace": 0.3} -) -plt.show() -``` - -## Subsetting and Indexing - -Indexing of Raster objects is provided by several methods: - -The ``Raster[keys]`` method enables key-based indexing using a name of a -RasterLayer, or a list of names. Direct subsetting of a Raster object instance -returns a RasterLayer if only a single label is used, otherwise it always -returns a new Raster object containing only the selected layers. - -The ``Raster.iloc[int, list, tuple, slice]`` method allows a Raster object -instance to be subset using integer-based indexing or slicing. The ``iloc`` -method returns a RasterLayer object if only a single index is used, otherwise -it always returns a new Raster object containing only the selected layers. - -Subsetting of a Raster object instance can also occur by using attribute names -in the form of ``Raster.name_of_layer``. Because only a single RasterLayer can -be subset at one time using this approach, a RasterLayer object is always -returned. - -Examples of methods to subset a Raster object: - -```{python} -# subset based on position -single_layer = stack.iloc[0] - -# subset using a slice -new_raster_obj = stack.iloc[0:3] - -# subset using labels -single_layer = stack['lsat7_2000_10'] -single_layer = stack.lsat7_2000_10 - -# list or tuple of keys -new_raster_obj = stack[('lsat7_2000_10', 'lsat7_2000_20')] -``` - -Iterate through RasterLayers individually: - -```{python} -for name, layer in stack.items(): - print(name, layer) -``` - -Replace a RasterLayer with another: - -```{python} -stack.iloc[0] = Raster(nc.band7).iloc[0] - -stack.iloc[0].plot() -plt.show() -``` - -## Appending and Dropping Layers - -Append layers from another Raster to the stack. Duplicate names are -automatically given a suffix. - -```{python} -stack.append(Raster(nc.band7), in_place=True) -stack.names -``` - -Rename RasterLayers using a dict of old_name : new_name pairs: - -```{python} -stack.names -stack.rename({'lsat7_2000_30': 'new_name'}, in_place=True) -stack.names -stack.new_name -stack['new_name'] -``` - -Drop a RasterLayer: - -```{python} -stack.names -stack.drop(labels='lsat7_2000_70_1', in_place=True) -stack.names -``` - -## Integration with Pandas - -Data from a Raster object can converted into a `Pandas.DataDrame`, with each -pixel representing by a row, and columns reflecting the x, y coordinates and -the values of each RasterLayer in the Raster object: - -```{python} -import pandas as pd - -df = stack.to_pandas(max_pixels=50000, resampling='nearest') -df.head() -``` - -The original raster is up-sampled based on max_pixels and the resampling -method, which uses all of resampling methods available in the underlying -rasterio library for decimated reads. - -## Saving a Raster to File - -Save a Raster: - -```{python} -import tempfile - -tmp_tif = tempfile.NamedTemporaryFile().name + '.tif' -newstack = stack.write(file_path=tmp_tif, nodata=-9999) -newstack.new_name.read() -newstack = None -``` +--- +title: "Quick start" +format: + html: + code-fold: false + toc: true +jupyter: python3 +--- + +## Initiating a Raster Object + +We are going to use a set of Landsat 7 bands contained within the nc example +data: + +```{python} +from pyspatialml import Raster +import pyspatialml.datasets.nc as nc +import matplotlib.pyplot as plt + +predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] +``` + +These raster datasets are aligned in terms of their extent and coordinate +reference systems. We can 'stack' these into a Raster class so that we can +perform machine learning related operations on the set of rasters: + +```{python} +stack = Raster(predictors) +``` + +When a Raster object is created, the names to each layer are automatically +created based on syntactically-correct versions of the file basenames: + +```{python} +stack.names +``` + +Color ramps and matplotlib.colors.Normalize objects can be assigned to each +RasterLayer in the object using the `cmap` and `norm` attributes for +convenient in plotting: + +```{python} +stack.lsat7_2000_10.cmap = "Blues" +stack.lsat7_2000_20.cmap = "Greens" +stack.lsat7_2000_30.cmap = "Reds" +stack.lsat7_2000_40.cmap = "RdPu" +stack.lsat7_2000_50.cmap = "autumn" +stack.lsat7_2000_70.cmap = "hot" + +stack.plot( + title_fontsize=8, + label_fontsize=6, + legend_fontsize=6, + names=["B1", "B2", "B3", "B4", "B5", "B7"], + fig_kwds={"figsize": (8, 4)}, + subplots_kwds={"wspace": 0.3} +) +plt.show() +``` + +## Subsetting and Indexing + +Indexing of Raster objects is provided by several methods: + +The ``Raster[keys]`` method enables key-based indexing using a name of a +RasterLayer, or a list of names. Direct subsetting of a Raster object instance +returns a RasterLayer if only a single label is used, otherwise it always +returns a new Raster object containing only the selected layers. + +The ``Raster.iloc[int, list, tuple, slice]`` method allows a Raster object +instance to be subset using integer-based indexing or slicing. The ``iloc`` +method returns a RasterLayer object if only a single index is used, otherwise +it always returns a new Raster object containing only the selected layers. + +Subsetting of a Raster object instance can also occur by using attribute names +in the form of ``Raster.name_of_layer``. Because only a single RasterLayer can +be subset at one time using this approach, a RasterLayer object is always +returned. + +Examples of methods to subset a Raster object: + +```{python} +# subset based on position +single_layer = stack.iloc[0] + +# subset using a slice +new_raster_obj = stack.iloc[0:3] + +# subset using labels +single_layer = stack['lsat7_2000_10'] +single_layer = stack.lsat7_2000_10 + +# list or tuple of keys +new_raster_obj = stack[('lsat7_2000_10', 'lsat7_2000_20')] +``` + +Iterate through RasterLayers individually: + +```{python} +for name, layer in stack.items(): + print(name, layer) +``` + +Replace a RasterLayer with another: + +```{python} +stack.iloc[0] = Raster(nc.band7).iloc[0] + +stack.iloc[0].plot() +plt.show() +``` + +## Appending and Dropping Layers + +Append layers from another Raster to the stack. Duplicate names are +automatically given a suffix. + +```{python} +stack.append(Raster(nc.band7), in_place=True) +stack.names +``` + +Rename RasterLayers using a dict of old_name : new_name pairs: + +```{python} +stack.names +stack.rename({'lsat7_2000_30': 'new_name'}, in_place=True) +stack.names +stack.new_name +stack['new_name'] +``` + +Drop a RasterLayer: + +```{python} +stack.names +stack.drop(labels='lsat7_2000_70_1', in_place=True) +stack.names +``` + +## Integration with Pandas + +Data from a Raster object can converted into a `Pandas.DataDrame`, with each +pixel representing by a row, and columns reflecting the x, y coordinates and +the values of each RasterLayer in the Raster object: + +```{python} +import pandas as pd + +df = stack.to_pandas(max_pixels=50000, resampling='nearest') +df.head() +``` + +The original raster is up-sampled based on max_pixels and the resampling +method, which uses all of resampling methods available in the underlying +rasterio library for decimated reads. + +## Saving a Raster to File + +Save a Raster: + +```{python} +import tempfile + +tmp_tif = tempfile.NamedTemporaryFile().name + '.tif' +newstack = stack.write(file_path=tmp_tif, nodata=-9999) +newstack.new_name.read() +newstack = None +``` diff --git a/docs/installation.qmd b/docs/installation.qmd index a465437..70fdc72 100644 --- a/docs/installation.qmd +++ b/docs/installation.qmd @@ -1,24 +1,24 @@ ---- -title: "Installation" -format: - html: - code-fold: false -jupyter: python3 ---- - -Pyspatialml is available on PyPI and can be installed in the usual manner with: - -```{python} -#| eval: false -pip install Pyspatialml -``` - -The development version, which is more up-to-date with changes to the package -especially during these earlier stages of development, can be installed -directly via: - -```{python} -#| eval: false -pip install git+https://github.com/stevenpawley/Pyspatialml -``` - +--- +title: "Installation" +format: + html: + code-fold: false +jupyter: python3 +--- + +Pyspatialml is available on PyPI and can be installed in the usual manner with: + +```{python} +#| eval: false +pip install Pyspatialml +``` + +The development version, which is more up-to-date with changes to the package +especially during these earlier stages of development, can be installed +directly via: + +```{python} +#| eval: false +pip install git+https://github.com/stevenpawley/Pyspatialml +``` + diff --git a/docs/landcover.qmd b/docs/landcover.qmd index 7d55b02..d9d9b80 100644 --- a/docs/landcover.qmd +++ b/docs/landcover.qmd @@ -1,210 +1,210 @@ ---- -title: "Landcover classification" -format: - html: - code-fold: false -jupyter: python3 ---- - -Landcover classification is a common task in remote sensing. This example -demonstrates how to extract training data from a raster and vector data, train -a classifier, and predict landcover classes on a raster. - -## Data - -The data used in this example is from the Landsat 7 ETM+ sensor, and represents -an extract of data derived from the GRASS GIS North Carolina example dataset. -The data consists of 6 bands (1, 2, 3, 4, 5, 7) and labelled pixels. The labelled -pixels are used as training data for the classifier. The data is stored in the -`pyspatialml.datasets` module. - -## Extraction Training Data - -Load some training data in the form of polygons, points and labelled pixels in -``geopandas.GeoDataFrame`` objects. We will also generate some line geometries -by converting the polygon boundaries into linestrings. All of these geometry -types can be used to spatially query pixel values in a Raster object, however -each GeoDataFrame must contain only one type of geometry (i.e. either shapely -points, polygons or linestrings). - -```{python} -from pyspatialml import Raster -from pyspatialml.datasets import nc -from copy import deepcopy -import os -import numpy as np -import tempfile -import geopandas -import rasterio.plot -import matplotlib.pyplot as plt - -training_py = geopandas.read_file(nc.polygons) -training_pt = geopandas.read_file(nc.points) -training_px = rasterio.open(nc.labelled_pixels) -training_lines = deepcopy(training_py) -training_lines['geometry'] = training_lines.geometry.boundary -``` - -Show training data points and a single raster band using numpy and matplotlib: - -```{python} -predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] -stack = Raster(predictors) - -fig, ax = plt.subplots(figsize=(9, 9)) -stack.lsat7_2000_70.plot(ax=ax) - -training_py.plot(column="label", ax=ax, legend=True) -plt.show() -``` - -Pixel values in the Raster object can be spatially queried using the -`extract_vector` and `extract_raster` methods. In addition, the -`extract_xy` method can be used to query pixel values using a 2d array of x -and y coordinates. - -The `extract_vector` method accepts a Geopandas GeoDataFrame as the -`gdf` argument. For GeoDataFrames containing shapely point geometries, the -closest pixel to each point is sampled. For shapely polygon geometries, all -pixels whose centres are inside the polygon are sampled. For shapely -linestring geometries, every pixel touched by the line is sampled. For all -geometry types, pixel values are queries for each geometry separately. This -means that overlapping polygons or points that fall within the same pixel with -cause the same pixel to be sampled multiple times. - -By default, the extract functions return a Geopandas GeoDataFrame of point -geometries and the DataFrame containing the extracted pixels, with the column -names set by the names of the raster datasets in the Raster object. The user -can also use the `return_array=True` argument, which instead of returning a -DataFrame will return three masked numpy arrays (ids, X, xy) containing the -geodataframe index positions, extracted pixel values, and the spatial -coordinates of the sampled pixels. These arrays are masked arrays. - -The `extract_raster` method can also be used to spatially query pixel values -from a Raster object using another raster containing labelled pixels. This -raster has to be spatially aligned with the Raster object. The values of the -labelled pixels are returned along with the queried pixel values. - -```{python} -# Extract data from rasters at the training point locations: -df_points = stack.extract_vector(training_pt) -df_polygons = stack.extract_vector(training_py) -df_lines = stack.extract_vector(training_lines) -``` - -For any vector features, a GeoDataFrame is returned containing the extracted -pixel values. A pandas.MultiIndex is used to relate the pixels back to the -original geometries, with the `pixel_idx` index referring to the index of each -pixel, and the `geometry_idx` referring to the index of the original geometry -in the supplied GeoDataFrame. The pixel values themselves are represented as -`shapely.geometry.Point` objects. These will need to be joined back with the -columns of the vector features to get the labelled classes. Here we will join -the extracted pixels using the "id" column and the GeoDataFrame index of the -vector features: - -```{python} -# Join the extracted values with other columns from the training data -df_points["id"] = training_pt["id"].values -df_points = df_points.dropna() -df_points.head() - -df_polygons = df_polygons.merge( - right=training_py.loc[:, ["label", "id"]], - left_on="geometry_idx", - right_on="index", - right_index=True -) -``` - -If the training data is from labelled pixels in a raster, then the extracted -data will contain a "value" column that contains the pixel labels: - -```{python} -df_raster = stack.extract_raster(training_px) -``` - -## Model Training - -Next we can train a logistic regression classifier: - -```{python} -from sklearn.linear_model import LogisticRegressionCV -from sklearn.preprocessing import StandardScaler -from sklearn.pipeline import Pipeline -from sklearn.model_selection import cross_validate - -# define the classifier with standardization of the input features in a -# pipeline -lr = Pipeline( - [('scaling', StandardScaler()), - ('classifier', LogisticRegressionCV(n_jobs=-1))]) - -# remove NaNs from training data -df_polygons = df_polygons.dropna() - -# fit the classifier -X = df_polygons.drop(columns=["id", "label", "geometry"]).values -y = df_polygons["id"].values -lr.fit(X, y) -``` - -After defining a classifier, a typical step consists of performing a -cross-validation to evaluate the performance of the model. Scikit-learn -provides the cross_validate function for this purpose. In comparison to -non-spatial data, spatial data can be spatially correlated, which potentially -can mean that geographically proximal samples may not represent truely -independent samples if they are within the autocorrelation range of some of the -predictors. This will lead to overly optimistic performance measures if samples -in the training dataset / cross-validation partition are strongly spatially -correlated with samples in the test dataset / cross-validation partition. - -In this case, performing cross-validation using groups is useful, because these -groups can represent spatial clusters of training samples, and samples from the -same group will never occur in both the training and test partitions of a -cross-validation. Here we can use the polygon indices as the groups, i.e. -pixels within the same polygon will not be split into training and test -partitions: - -```{python} -scores = cross_validate( - estimator=lr, - X=X, - y=y, - groups=df_polygons.index.droplevel("pixel_idx"), - scoring="accuracy", - cv=3, - n_jobs=1, -) -np.round(scores['test_score'].mean(), 2) -``` - -## Raster Prediction - -Prediction on the Raster object is performed using the `predict` method. -The `estimator` is the only required argument. If the `file_path` argument -is not specified then the result is automatically written to a temporary file. -The predict method returns an rasterio.io.DatasetReader object which is open. - -```{python} -# prediction -result = stack.predict(estimator=lr, dtype='int16', nodata=0) -result_probs = stack.predict_proba(estimator=lr) - -# plot classification result -result.iloc[0].cmap = "Dark2" -result.iloc[0].categorical = True - -result.plot() -plt.show() -``` - -The `predict_proba` method can be used to output class probabilities as -a multi-band raster (a band for each class probability). In the latter case, -`indexes` can also be supplied if you only want to output the probabilities -for a particular class, or list of classes, by supplying the indices of those -classes: - -```{python} -result_probs.plot() -plt.show() -``` +--- +title: "Landcover classification" +format: + html: + code-fold: false +jupyter: python3 +--- + +Landcover classification is a common task in remote sensing. This example +demonstrates how to extract training data from a raster and vector data, train +a classifier, and predict landcover classes on a raster. + +## Data + +The data used in this example is from the Landsat 7 ETM+ sensor, and represents +an extract of data derived from the GRASS GIS North Carolina example dataset. +The data consists of 6 bands (1, 2, 3, 4, 5, 7) and labelled pixels. The labelled +pixels are used as training data for the classifier. The data is stored in the +`pyspatialml.datasets` module. + +## Extraction Training Data + +Load some training data in the form of polygons, points and labelled pixels in +``geopandas.GeoDataFrame`` objects. We will also generate some line geometries +by converting the polygon boundaries into linestrings. All of these geometry +types can be used to spatially query pixel values in a Raster object, however +each GeoDataFrame must contain only one type of geometry (i.e. either shapely +points, polygons or linestrings). + +```{python} +from pyspatialml import Raster +from pyspatialml.datasets import nc +from copy import deepcopy +import os +import numpy as np +import tempfile +import geopandas +import rasterio.plot +import matplotlib.pyplot as plt + +training_py = geopandas.read_file(nc.polygons) +training_pt = geopandas.read_file(nc.points) +training_px = rasterio.open(nc.labelled_pixels) +training_lines = deepcopy(training_py) +training_lines['geometry'] = training_lines.geometry.boundary +``` + +Show training data points and a single raster band using numpy and matplotlib: + +```{python} +predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] +stack = Raster(predictors) + +fig, ax = plt.subplots(figsize=(9, 9)) +stack.lsat7_2000_70.plot(ax=ax) + +training_py.plot(column="label", ax=ax, legend=True) +plt.show() +``` + +Pixel values in the Raster object can be spatially queried using the +`extract_vector` and `extract_raster` methods. In addition, the +`extract_xy` method can be used to query pixel values using a 2d array of x +and y coordinates. + +The `extract_vector` method accepts a Geopandas GeoDataFrame as the +`gdf` argument. For GeoDataFrames containing shapely point geometries, the +closest pixel to each point is sampled. For shapely polygon geometries, all +pixels whose centres are inside the polygon are sampled. For shapely +linestring geometries, every pixel touched by the line is sampled. For all +geometry types, pixel values are queries for each geometry separately. This +means that overlapping polygons or points that fall within the same pixel with +cause the same pixel to be sampled multiple times. + +By default, the extract functions return a Geopandas GeoDataFrame of point +geometries and the DataFrame containing the extracted pixels, with the column +names set by the names of the raster datasets in the Raster object. The user +can also use the `return_array=True` argument, which instead of returning a +DataFrame will return three masked numpy arrays (ids, X, xy) containing the +geodataframe index positions, extracted pixel values, and the spatial +coordinates of the sampled pixels. These arrays are masked arrays. + +The `extract_raster` method can also be used to spatially query pixel values +from a Raster object using another raster containing labelled pixels. This +raster has to be spatially aligned with the Raster object. The values of the +labelled pixels are returned along with the queried pixel values. + +```{python} +# Extract data from rasters at the training point locations: +df_points = stack.extract_vector(training_pt) +df_polygons = stack.extract_vector(training_py) +df_lines = stack.extract_vector(training_lines) +``` + +For any vector features, a GeoDataFrame is returned containing the extracted +pixel values. A pandas.MultiIndex is used to relate the pixels back to the +original geometries, with the `pixel_idx` index referring to the index of each +pixel, and the `geometry_idx` referring to the index of the original geometry +in the supplied GeoDataFrame. The pixel values themselves are represented as +`shapely.geometry.Point` objects. These will need to be joined back with the +columns of the vector features to get the labelled classes. Here we will join +the extracted pixels using the "id" column and the GeoDataFrame index of the +vector features: + +```{python} +# Join the extracted values with other columns from the training data +df_points["id"] = training_pt["id"].values +df_points = df_points.dropna() +df_points.head() + +df_polygons = df_polygons.merge( + right=training_py.loc[:, ["label", "id"]], + left_on="geometry_idx", + right_on="index", + right_index=True +) +``` + +If the training data is from labelled pixels in a raster, then the extracted +data will contain a "value" column that contains the pixel labels: + +```{python} +df_raster = stack.extract_raster(training_px) +``` + +## Model Training + +Next we can train a logistic regression classifier: + +```{python} +from sklearn.linear_model import LogisticRegressionCV +from sklearn.preprocessing import StandardScaler +from sklearn.pipeline import Pipeline +from sklearn.model_selection import cross_validate + +# define the classifier with standardization of the input features in a +# pipeline +lr = Pipeline( + [('scaling', StandardScaler()), + ('classifier', LogisticRegressionCV(n_jobs=-1))]) + +# remove NaNs from training data +df_polygons = df_polygons.dropna() + +# fit the classifier +X = df_polygons.drop(columns=["id", "label", "geometry"]).values +y = df_polygons["id"].values +lr.fit(X, y) +``` + +After defining a classifier, a typical step consists of performing a +cross-validation to evaluate the performance of the model. Scikit-learn +provides the cross_validate function for this purpose. In comparison to +non-spatial data, spatial data can be spatially correlated, which potentially +can mean that geographically proximal samples may not represent truely +independent samples if they are within the autocorrelation range of some of the +predictors. This will lead to overly optimistic performance measures if samples +in the training dataset / cross-validation partition are strongly spatially +correlated with samples in the test dataset / cross-validation partition. + +In this case, performing cross-validation using groups is useful, because these +groups can represent spatial clusters of training samples, and samples from the +same group will never occur in both the training and test partitions of a +cross-validation. Here we can use the polygon indices as the groups, i.e. +pixels within the same polygon will not be split into training and test +partitions: + +```{python} +scores = cross_validate( + estimator=lr, + X=X, + y=y, + groups=df_polygons.index.droplevel("pixel_idx"), + scoring="accuracy", + cv=3, + n_jobs=1, +) +np.round(scores['test_score'].mean(), 2) +``` + +## Raster Prediction + +Prediction on the Raster object is performed using the `predict` method. +The `estimator` is the only required argument. If the `file_path` argument +is not specified then the result is automatically written to a temporary file. +The predict method returns an rasterio.io.DatasetReader object which is open. + +```{python} +# prediction +result = stack.predict(estimator=lr, dtype='int16', nodata=0) +result_probs = stack.predict_proba(estimator=lr) + +# plot classification result +result.iloc[0].cmap = "Dark2" +result.iloc[0].categorical = True + +result.plot() +plt.show() +``` + +The `predict_proba` method can be used to output class probabilities as +a multi-band raster (a band for each class probability). In the latter case, +`indexes` can also be supplied if you only want to output the probabilities +for a particular class, or list of classes, by supplying the indices of those +classes: + +```{python} +result_probs.plot() +plt.show() +``` diff --git a/docs/multitarget-regression-soil-properties.qmd b/docs/multitarget-regression-soil-properties.qmd index ce47f2f..16b39dd 100644 --- a/docs/multitarget-regression-soil-properties.qmd +++ b/docs/multitarget-regression-soil-properties.qmd @@ -1,284 +1,284 @@ ---- -title: "Multi-Target Spatial Prediction using the Meuse Dataset" -format: - html: - code-fold: false -jupyter: python3 ---- - -Here we are using the meuse dataset which is included in the pyspatialml package as an example of performing a spatial model and prediction. We can access the datasets using the `pyspatialml.datasets` module: - -```{python} -from copy import deepcopy -from tempfile import NamedTemporaryFile -import geopandas as gpd -import numpy as np -from pyspatialml import Raster -from pyspatialml.preprocessing import xy_coordinates, distance_to_corners -import pyspatialml.datasets.meuse as ms - -import matplotlib as mpl -import matplotlib.pyplot as plt -from matplotlib import cm -``` - -```{python} -predictor_files = ms.predictors -training_pts_file = ms.meuse -``` - -```{python} -stack = Raster(predictor_files) -stack.names -``` - -Pyspatialml implements pandas-style indexing for `Raster` objects, using `Raster.loc` to index by the name of the raster, and `Raster.iloc` to select by index. This method also accepts slices. Label-based indexing is also provided directly by the __getattr_ magic method, i.e. `Raster[name]` or for multiple layers `Raster[(names)]`. - -For example we can remove layers from Raster object using the `Raster.drop` method, or by subsetting the raster: - -```{python} -stack.drop('ffreq') -``` - -We can store matplotlib cmaps as an attribute within each layer in the Raster: - -```{python} -stack.chnl_dist.cmap = 'RdBu' -stack.dem.cmap = 'terrain' -stack.dist.cmap = 'Reds' -stack.landimg2.cmap = 'Greys' -stack.landimg3.cmap = 'Greys' -stack.landimg4.cmap = 'Greys' -stack.landimg4.cmap = 'Greys' -stack.mrvbf.cmap = 'jet' -stack.rsp.cmap = 'gnuplot2' -stack.slope.cmap = 'PuRd' -stack.soil.cmap = 'Set2' -stack.twi.cmap = 'coolwarm' -``` - -Plot the predictors in the Raster object as a raster matrix: - -```{python} -mpl.style.use('seaborn-v0_8') -axs = stack.plot(figsize=(9, 7)) -ax = axs.flatten()[10] -im = ax.images -im[0].colorbar.set_ticks([1,2,3]) -ax = axs.flatten()[8] -ax.tick_params(axis='x', labelrotation=65) - -plt.tight_layout() -plt.show() -``` - -## Feature Engineering - -We want the prediction results to be dependent on the spatial locations of the training data. So to include spatial information, coordinate grids can be generated and added to the Raster object: - -```{python} -xy_layer = xy_coordinates( - layer=stack.iloc[0], - file_path=NamedTemporaryFile(suffix=".tif").name -) -``` - -```{python} -xy_layer = xy_coordinates( - layer=stack.iloc[0], - file_path=NamedTemporaryFile(suffix=".tif").name -) - -edms = distance_to_corners( - layer=stack.iloc[0], - file_path=NamedTemporaryFile(suffix=".tif").name -) -edms.rename( - {old: new for (old, new) in zip(edms.names, ["tl", "tr", "bl", "br", "c"])}, - in_place=True -) - -edms.plot() -plt.show() -``` - -Append them to the Raster object: - -```{python} -stack = stack.append([xy_layer, edms]) -``` - -Plot the new predictors: - -```{python} -axs = stack.plot(figsize=(9, 7)) -ax = axs.flatten()[10] -im = ax.images -im[0].colorbar.set_ticks([1,2,3]) -ax = axs.flatten()[8] -ax.tick_params(axis='x', labelrotation=65) - -plt.tight_layout() -plt.show() -``` - -The area that is filled by some of the grids is different. This doesn't matter for the prediction because pixels in the Raster object that include some NaNs in some of the layers will be removed. However, the plots could potentially be given a cleaner look. We can use the Raster.intersect method to fix this: - -```{python} -stack = stack.intersect() -``` - -```{python} -axs = stack.plot(figsize=(9, 7)) -ax = axs.flatten()[10] -im = ax.images -im[0].colorbar.set_ticks([1,2,3]) -ax = axs.flatten()[8] -ax.tick_params(axis='x', labelrotation=65) - -plt.tight_layout() -plt.show() -``` - -## Read the Meuse Dataset - -```{python} -training_pts = gpd.read_file(training_pts_file) -training_pts.head() -``` - -Plot the training points: - -```{python} -from mpl_toolkits.axes_grid1 import make_axes_locatable - -fig, axs = plt.subplots(2, 3, figsize=(8.5, 7)) - -for i, (ax, target) in enumerate(zip(axs.ravel(), ['cadmium', 'copper', 'lead', 'zinc', 'om'])): - ax.set_title(target.title()) - divider = make_axes_locatable(ax) - cax = divider.append_axes("right", size="10%", pad=0.05) - training_pts.plot(column=target, legend=True, ax=ax, cax=cax, cmap='viridis') - - if i != 0: - ax.set_yticklabels([]) - - if i != 3: - ax.set_xticklabels([]) - else: - ax.tick_params(axis='x', labelrotation=65) - -fig.delaxes(axs.flatten()[i+1]) -plt.tight_layout() -plt.show() -``` - -## Extract Raster Values at the Training Point Locations - -Pixel values from a Raster object can be extracted using geometries within a geopandas.GeoDataFrame (points, lines, polygons) or by using labelled pixels from another raster with the same dimensions and crs. - -By default the extracted values are returned as a geopandas.GeoDataFrame that contains the data and the coordinates of the pixels: - -```{python} -training_df = stack.extract_vector(gdf=training_pts) - -training_df.index = training_df.index.get_level_values("geometry_idx") -training_df = training_df.merge( - training_pts.loc[:, ("lead", "cadmium", "copper", "zinc", "om")], - left_index=True, - right_index=True -) -``` - -```{python} -training_df = training_df.dropna() -training_df.head() -``` - -## Developing a Machine Learning Model - -Here we are going to create a machine learning pipeline that correctly handles categorical predictors via one-hot encoding: - -```{python} -stack.names -``` - -```{python} -from sklearn.pipeline import Pipeline -from sklearn.ensemble import ExtraTreesRegressor -from sklearn.preprocessing import OneHotEncoder -from sklearn.compose import ColumnTransformer - -soil_idx = [i for i, name in enumerate(stack.names) if name == 'soil'] - -trans = ColumnTransformer([ - ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), soil_idx) - ], remainder='passthrough') - -et = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234) -et = Pipeline([ - ('preproc', trans), - ('regressor', et)]) -``` - -Now we can separate our response and predictor variables and train the model: - -```{python} -X = training_df.loc[:, stack.names] -y = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']] -et.fit(X, y) -``` - -To evaluate the performance of the model, we will use 10-fold cross validation: - -```{python} -from sklearn.model_selection import cross_validate, KFold - -outer = KFold(n_splits=10, shuffle=True, random_state=1234) -scores = cross_validate(et, X, y, scoring='neg_mean_squared_error', cv=10, n_jobs=1) -rmse = np.sqrt(-scores['test_score']).mean() - -print("Our RMSE score is {}".format(rmse)) -``` - -## Feature Importances - -```{python} -ohe_names = deepcopy(list(stack.names)) -ohe_names.insert(soil_idx[0], 'soil1') -ohe_names.insert(soil_idx[0], 'soil2') -ohe_names = np.array(ohe_names) -``` - -```{python} -mpl.style.use('ggplot') - -fimp = et.named_steps['regressor'].feature_importances_ - -fig, ax = plt.subplots(figsize=(4, 6)) -ax.barh(y=ohe_names[fimp.argsort()], width=fimp[fimp.argsort()]) -ax.set_xlabel('Feature Importance Score') -plt.show() -``` - -## Prediction on the Raster object - -```{python} -preds = stack.predict(et) -preds.rename( - {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])}, - in_place=True -) -preds.lead.cmap = 'rainbow' -preds.cadmium.cmap = 'rainbow' -preds.copper.cmap = 'rainbow' -preds.zinc.cmap = 'rainbow' -preds.om.cmap = 'rainbow' -``` - -Plot the results: - -```{python} -preds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8)) -plt.show() -``` +--- +title: "Multi-Target Spatial Prediction using the Meuse Dataset" +format: + html: + code-fold: false +jupyter: python3 +--- + +Here we are using the meuse dataset which is included in the pyspatialml package as an example of performing a spatial model and prediction. We can access the datasets using the `pyspatialml.datasets` module: + +```{python} +from copy import deepcopy +from tempfile import NamedTemporaryFile +import geopandas as gpd +import numpy as np +from pyspatialml import Raster +from pyspatialml.preprocessing import xy_coordinates, distance_to_corners +import pyspatialml.datasets.meuse as ms + +import matplotlib as mpl +import matplotlib.pyplot as plt +from matplotlib import cm +``` + +```{python} +predictor_files = ms.predictors +training_pts_file = ms.meuse +``` + +```{python} +stack = Raster(predictor_files) +stack.names +``` + +Pyspatialml implements pandas-style indexing for `Raster` objects, using `Raster.loc` to index by the name of the raster, and `Raster.iloc` to select by index. This method also accepts slices. Label-based indexing is also provided directly by the __getattr_ magic method, i.e. `Raster[name]` or for multiple layers `Raster[(names)]`. + +For example we can remove layers from Raster object using the `Raster.drop` method, or by subsetting the raster: + +```{python} +stack.drop('ffreq') +``` + +We can store matplotlib cmaps as an attribute within each layer in the Raster: + +```{python} +stack.chnl_dist.cmap = 'RdBu' +stack.dem.cmap = 'terrain' +stack.dist.cmap = 'Reds' +stack.landimg2.cmap = 'Greys' +stack.landimg3.cmap = 'Greys' +stack.landimg4.cmap = 'Greys' +stack.landimg4.cmap = 'Greys' +stack.mrvbf.cmap = 'jet' +stack.rsp.cmap = 'gnuplot2' +stack.slope.cmap = 'PuRd' +stack.soil.cmap = 'Set2' +stack.twi.cmap = 'coolwarm' +``` + +Plot the predictors in the Raster object as a raster matrix: + +```{python} +mpl.style.use('seaborn-v0_8') +axs = stack.plot(figsize=(9, 7)) +ax = axs.flatten()[10] +im = ax.images +im[0].colorbar.set_ticks([1,2,3]) +ax = axs.flatten()[8] +ax.tick_params(axis='x', labelrotation=65) + +plt.tight_layout() +plt.show() +``` + +## Feature Engineering + +We want the prediction results to be dependent on the spatial locations of the training data. So to include spatial information, coordinate grids can be generated and added to the Raster object: + +```{python} +xy_layer = xy_coordinates( + layer=stack.iloc[0], + file_path=NamedTemporaryFile(suffix=".tif").name +) +``` + +```{python} +xy_layer = xy_coordinates( + layer=stack.iloc[0], + file_path=NamedTemporaryFile(suffix=".tif").name +) + +edms = distance_to_corners( + layer=stack.iloc[0], + file_path=NamedTemporaryFile(suffix=".tif").name +) +edms.rename( + {old: new for (old, new) in zip(edms.names, ["tl", "tr", "bl", "br", "c"])}, + in_place=True +) + +edms.plot() +plt.show() +``` + +Append them to the Raster object: + +```{python} +stack = stack.append([xy_layer, edms]) +``` + +Plot the new predictors: + +```{python} +axs = stack.plot(figsize=(9, 7)) +ax = axs.flatten()[10] +im = ax.images +im[0].colorbar.set_ticks([1,2,3]) +ax = axs.flatten()[8] +ax.tick_params(axis='x', labelrotation=65) + +plt.tight_layout() +plt.show() +``` + +The area that is filled by some of the grids is different. This doesn't matter for the prediction because pixels in the Raster object that include some NaNs in some of the layers will be removed. However, the plots could potentially be given a cleaner look. We can use the Raster.intersect method to fix this: + +```{python} +stack = stack.intersect() +``` + +```{python} +axs = stack.plot(figsize=(9, 7)) +ax = axs.flatten()[10] +im = ax.images +im[0].colorbar.set_ticks([1,2,3]) +ax = axs.flatten()[8] +ax.tick_params(axis='x', labelrotation=65) + +plt.tight_layout() +plt.show() +``` + +## Read the Meuse Dataset + +```{python} +training_pts = gpd.read_file(training_pts_file) +training_pts.head() +``` + +Plot the training points: + +```{python} +from mpl_toolkits.axes_grid1 import make_axes_locatable + +fig, axs = plt.subplots(2, 3, figsize=(8.5, 7)) + +for i, (ax, target) in enumerate(zip(axs.ravel(), ['cadmium', 'copper', 'lead', 'zinc', 'om'])): + ax.set_title(target.title()) + divider = make_axes_locatable(ax) + cax = divider.append_axes("right", size="10%", pad=0.05) + training_pts.plot(column=target, legend=True, ax=ax, cax=cax, cmap='viridis') + + if i != 0: + ax.set_yticklabels([]) + + if i != 3: + ax.set_xticklabels([]) + else: + ax.tick_params(axis='x', labelrotation=65) + +fig.delaxes(axs.flatten()[i+1]) +plt.tight_layout() +plt.show() +``` + +## Extract Raster Values at the Training Point Locations + +Pixel values from a Raster object can be extracted using geometries within a geopandas.GeoDataFrame (points, lines, polygons) or by using labelled pixels from another raster with the same dimensions and crs. + +By default the extracted values are returned as a geopandas.GeoDataFrame that contains the data and the coordinates of the pixels: + +```{python} +training_df = stack.extract_vector(gdf=training_pts) + +training_df.index = training_df.index.get_level_values("geometry_idx") +training_df = training_df.merge( + training_pts.loc[:, ("lead", "cadmium", "copper", "zinc", "om")], + left_index=True, + right_index=True +) +``` + +```{python} +training_df = training_df.dropna() +training_df.head() +``` + +## Developing a Machine Learning Model + +Here we are going to create a machine learning pipeline that correctly handles categorical predictors via one-hot encoding: + +```{python} +stack.names +``` + +```{python} +from sklearn.pipeline import Pipeline +from sklearn.ensemble import ExtraTreesRegressor +from sklearn.preprocessing import OneHotEncoder +from sklearn.compose import ColumnTransformer + +soil_idx = [i for i, name in enumerate(stack.names) if name == 'soil'] + +trans = ColumnTransformer([ + ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), soil_idx) + ], remainder='passthrough') + +et = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234) +et = Pipeline([ + ('preproc', trans), + ('regressor', et)]) +``` + +Now we can separate our response and predictor variables and train the model: + +```{python} +X = training_df.loc[:, stack.names] +y = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']] +et.fit(X, y) +``` + +To evaluate the performance of the model, we will use 10-fold cross validation: + +```{python} +from sklearn.model_selection import cross_validate, KFold + +outer = KFold(n_splits=10, shuffle=True, random_state=1234) +scores = cross_validate(et, X, y, scoring='neg_mean_squared_error', cv=10, n_jobs=1) +rmse = np.sqrt(-scores['test_score']).mean() + +print("Our RMSE score is {}".format(rmse)) +``` + +## Feature Importances + +```{python} +ohe_names = deepcopy(list(stack.names)) +ohe_names.insert(soil_idx[0], 'soil1') +ohe_names.insert(soil_idx[0], 'soil2') +ohe_names = np.array(ohe_names) +``` + +```{python} +mpl.style.use('ggplot') + +fimp = et.named_steps['regressor'].feature_importances_ + +fig, ax = plt.subplots(figsize=(4, 6)) +ax.barh(y=ohe_names[fimp.argsort()], width=fimp[fimp.argsort()]) +ax.set_xlabel('Feature Importance Score') +plt.show() +``` + +## Prediction on the Raster object + +```{python} +preds = stack.predict(et) +preds.rename( + {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])}, + in_place=True +) +preds.lead.cmap = 'rainbow' +preds.cadmium.cmap = 'rainbow' +preds.copper.cmap = 'rainbow' +preds.zinc.cmap = 'rainbow' +preds.om.cmap = 'rainbow' +``` + +Plot the results: + +```{python} +preds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8)) +plt.show() +``` diff --git a/docs/plotting.qmd b/docs/plotting.qmd index ac14ee0..ccfb02c 100644 --- a/docs/plotting.qmd +++ b/docs/plotting.qmd @@ -1,69 +1,69 @@ ---- -title: "Plotting" -format: - html: - code-fold: false - toc: true -jupyter: python3 ---- - -Both `Raster` and `RasterLayer` objects include basic plotting methods. The -plot method for a `RasterLayer` object produces a single raster plot using the -`matplotlib.pyplot.imshow` method. - -For convenience, plot settings such as color ramps and stretches can also be -set for each RasterLayer using the `RasterLayer.cmap` that support matplotlib -cmap's, and the `RasterLayer.norm` attribute to associate a -`matplotlib.colors.Normalize` stretch with each RasterLayer: - -To plot a single RasterLayer: - -```{python} -from pyspatialml import Raster -from pyspatialml.datasets import nc -import matplotlib.pyplot as plt - -stack = Raster([nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]) - -# set RasterLayer color table -stack.lsat7_2000_10.cmap = "plasma" - -# plot a single layer using an existing axis -fig, ax = plt.subplots() -stack.lsat7_2000_10.plot(ax=ax) -plt.show() -``` - -For RasterLayers that represent categorical data types, e.g. land cover, then -the `RasterLayer.categorical=True` attribute will cause the cmap to be -converted to a discrete scale. - -The default plot method for a `Raster` object produces a raster-matrix plot of -the individual RasterLayers. By default this plot preserves the plotting -attributes of the individual rasters: - -Plot all RasterLayers in a Raster object: - -```{python} -stack.lsat7_2000_10.cmap = "Blues" -stack.lsat7_2000_20.cmap = "Greens" -stack.lsat7_2000_30.cmap = "Reds" -stack.lsat7_2000_40.cmap = "RdPu" -stack.lsat7_2000_50.cmap = "autumn" -stack.lsat7_2000_70.cmap = "hot" - -stack.plot( - title_fontsize=8, - label_fontsize=6, - legend_fontsize=6, - names=["B1", "B2", "B3", "B4", "B5", "B7"], - fig_kwds={"figsize": (8, 4)}, - subplots_kwds={"wspace": 0.3} -) -plt.show() -``` - -The `Raster.plot` method also provides `cmap` and `norm` arguments that can be -used to override the settings of the individual RasterLayers. Additional -settings can be passed to control plot layout using the `figure_kwds`, -`legend_kwds` and `subplots_kwds` arguments. +--- +title: "Plotting" +format: + html: + code-fold: false + toc: true +jupyter: python3 +--- + +Both `Raster` and `RasterLayer` objects include basic plotting methods. The +plot method for a `RasterLayer` object produces a single raster plot using the +`matplotlib.pyplot.imshow` method. + +For convenience, plot settings such as color ramps and stretches can also be +set for each RasterLayer using the `RasterLayer.cmap` that support matplotlib +cmap's, and the `RasterLayer.norm` attribute to associate a +`matplotlib.colors.Normalize` stretch with each RasterLayer: + +To plot a single RasterLayer: + +```{python} +from pyspatialml import Raster +from pyspatialml.datasets import nc +import matplotlib.pyplot as plt + +stack = Raster([nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]) + +# set RasterLayer color table +stack.lsat7_2000_10.cmap = "plasma" + +# plot a single layer using an existing axis +fig, ax = plt.subplots() +stack.lsat7_2000_10.plot(ax=ax) +plt.show() +``` + +For RasterLayers that represent categorical data types, e.g. land cover, then +the `RasterLayer.categorical=True` attribute will cause the cmap to be +converted to a discrete scale. + +The default plot method for a `Raster` object produces a raster-matrix plot of +the individual RasterLayers. By default this plot preserves the plotting +attributes of the individual rasters: + +Plot all RasterLayers in a Raster object: + +```{python} +stack.lsat7_2000_10.cmap = "Blues" +stack.lsat7_2000_20.cmap = "Greens" +stack.lsat7_2000_30.cmap = "Reds" +stack.lsat7_2000_40.cmap = "RdPu" +stack.lsat7_2000_50.cmap = "autumn" +stack.lsat7_2000_70.cmap = "hot" + +stack.plot( + title_fontsize=8, + label_fontsize=6, + legend_fontsize=6, + names=["B1", "B2", "B3", "B4", "B5", "B7"], + fig_kwds={"figsize": (8, 4)}, + subplots_kwds={"wspace": 0.3} +) +plt.show() +``` + +The `Raster.plot` method also provides `cmap` and `norm` arguments that can be +used to override the settings of the individual RasterLayers. Additional +settings can be passed to control plot layout using the `figure_kwds`, +`legend_kwds` and `subplots_kwds` arguments. diff --git a/docs/sampling.qmd b/docs/sampling.qmd index 29a08a9..3073e9a 100644 --- a/docs/sampling.qmd +++ b/docs/sampling.qmd @@ -1,43 +1,43 @@ ---- -title: "Random Sampling" -format: - html: - code-fold: false - toc: true -jupyter: python3 ---- - -## Random Uniform Sampling - -For many spatial models, it is common to take a random sample of the -predictors to represent a single class (i.e. an environmental background or -pseudo-absences in a binary classification model). The sample function is -supplied in the sampling module for this purpose: - -```{python} -from pyspatialml import Raster -import pyspatialml.datasets.nc as nc -import matplotlib.pyplot as plt - -predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] -stack = Raster(predictors) - -# extract training data using a random sample -df_rand = stack.sample(size=1000, random_state=1) -df_rand.plot() -``` - -## Stratified Random Sampling - -The sample function also enables stratified random sampling based on passing a -categorical raster dataset to the strata argument. The categorical raster -should spatially overlap with the dataset to be sampled, but it does not need -to be of the same grid resolution. This raster should be passed as a opened -rasterio dataset: - -```{python} -strata = Raster(nc.strata) -df_strata = stack.sample(size=5, strata=strata, random_state=1) -df_strata = df_strata.dropna() -df_strata +--- +title: "Random Sampling" +format: + html: + code-fold: false + toc: true +jupyter: python3 +--- + +## Random Uniform Sampling + +For many spatial models, it is common to take a random sample of the +predictors to represent a single class (i.e. an environmental background or +pseudo-absences in a binary classification model). The sample function is +supplied in the sampling module for this purpose: + +```{python} +from pyspatialml import Raster +import pyspatialml.datasets.nc as nc +import matplotlib.pyplot as plt + +predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] +stack = Raster(predictors) + +# extract training data using a random sample +df_rand = stack.sample(size=1000, random_state=1) +df_rand.plot() +``` + +## Stratified Random Sampling + +The sample function also enables stratified random sampling based on passing a +categorical raster dataset to the strata argument. The categorical raster +should spatially overlap with the dataset to be sampled, but it does not need +to be of the same grid resolution. This raster should be passed as a opened +rasterio dataset: + +```{python} +strata = Raster(nc.strata) +df_strata = stack.sample(size=5, strata=strata, random_state=1) +df_strata = df_strata.dropna() +df_strata ``` \ No newline at end of file diff --git a/docs/spatial-features.qmd b/docs/spatial-features.qmd index 20bf887..5b00189 100644 --- a/docs/spatial-features.qmd +++ b/docs/spatial-features.qmd @@ -1,151 +1,151 @@ ---- -title: "Incorporating Spatial Autocorrelation into Spatial Predictions" -format: - html: - code-fold: false -jupyter: python3 ---- - -Similarly to example 1, we are using the meuse dataset again to perform a multi-target prediction of soil properties using a regression model. However, in this case we will attempt to account for spatial autocorrelation in the model directly by generating new features that are based on the distance-weighted means of surrounding spatial locations. - -```{python} -import geopandas as gpd -import numpy as np -from tempfile import NamedTemporaryFile -from pyspatialml import Raster -import pyspatialml.datasets.meuse as ms -import matplotlib as mpl -import matplotlib.pyplot as plt -``` - -## Preparing the Raster Predictors - -Import the raster predictors from the `pyspatialml.datasets.meuse` module: - -```{python} -predictor_files = ms.predictors -training_pts_file = ms.meuse -stack = Raster(predictor_files) -stack.drop('ffreq') -``` - -In order to generate new features from surrounding spatial locations, we need their x,y coordinates, which will will add to the stack of the raster predictors using the `pyspatialml.preprocessing.xy_coordinates` function: - -```{python} -from pyspatialml.preprocessing import xy_coordinates - -xy_layers = xy_coordinates(stack.iloc[0], NamedTemporaryFile(suffix=".tif").name) -stack = stack.append(xy_layers, in_place=False) -``` - -Quickly plot the raster predictors: - -```{python} -mpl.style.use('seaborn-v0_8') -axs = stack.plot(figsize=(9, 7)) -ax = axs.flatten()[10] -im = ax.images -im[0].colorbar.set_ticks([1,2,3]) -ax = axs.flatten()[8] -ax.tick_params(axis='x', labelrotation=65) - -plt.tight_layout() -plt.show() -``` - -## Extract the Training Data - -Spatially query the raster predictors at the training point locations: - -```{python} -training_pts = gpd.read_file(training_pts_file) -training_df = stack.extract_vector(gdf=training_pts) - -training_df.index = training_df.index.get_level_values("geometry_idx") -training_df = training_df.merge( - training_pts.loc[:, ("lead", "cadmium", "copper", "zinc", "om")], - left_index=True, - right_index=True -) -training_df = training_df.dropna() -``` - -Split the response/target variables from the predictors: - -```{python} -X = training_df.loc[:, stack.names].values -y = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']].values -``` - -## Develop a Spatially-Lagged Machine Learning Model - -As well as using the ExtraTreeRegressor model which was also used in example 1, here we will use the custom `pyspatialml.estimators.SpatialLagRegressor` metalearner class to wrap the extratrees regressor into a model that adds a new feature based on the distance-weighted mean of spatially-proximal observations: - -```{python} -from sklearn.pipeline import Pipeline -from sklearn.ensemble import ExtraTreesRegressor -from sklearn.preprocessing import OneHotEncoder -from sklearn.compose import ColumnTransformer -from pyspatialml.transformers import KNNTransformer -from sklearn.model_selection import cross_validate, KFold -from sklearn.model_selection import GridSearchCV - -# define regressor -et = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234) - -soil_index = list(stack.names).index("soil") -xy_indexes = [list(stack.names).index(i) for i in ["x_coordinates", "y_coordinates"]] - -preproc = ColumnTransformer([ - ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), [soil_index]), - ('lags', KNNTransformer(weights='distance', measure="mean"), xy_indexes) -], remainder='passthrough') - -wflow = Pipeline([ - ('preproc', preproc), - ('regressor', et) -]) - -search_grid = {"preproc__lags__n_neighbors": [3, 5, 7, 9]} -inner = KFold(n_splits=3, shuffle=True, random_state=1234) -model = GridSearchCV(wflow, param_grid=search_grid, cv=inner, scoring="r2") -``` - -Fit the model and cross-validate: - -```{python} -model = model.fit(X, y) -model.best_params_ -``` - -```{python} -outer = KFold(n_splits=10, shuffle=True, random_state=1234) - -scores = cross_validate(model, X, y, scoring='neg_mean_squared_error', cv=outer, n_jobs=1) -rmse = np.sqrt(-scores['test_score']).mean() - -print("Our RMSE score is {}".format(rmse)) -``` - -Comparing the RMSE score the the score obtained in example 1, where the spatial structure of the training data was accounted for indirectly by added a variety of raster distance measures, we can see that the RMSE score is slightly improved. - -## Multi-Target Predictions - -```{python} -preds = stack.predict(model) -preds.rename( - {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])}, - in_place=True -) -preds.lead.cmap = 'rainbow' -preds.cadmium.cmap = 'rainbow' -preds.copper.cmap = 'rainbow' -preds.zinc.cmap = 'rainbow' -preds.om.cmap = 'rainbow' -``` - -```{python} -preds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8)) -plt.show() -``` - +--- +title: "Incorporating Spatial Autocorrelation into Spatial Predictions" +format: + html: + code-fold: false +jupyter: python3 +--- + +Similarly to example 1, we are using the meuse dataset again to perform a multi-target prediction of soil properties using a regression model. However, in this case we will attempt to account for spatial autocorrelation in the model directly by generating new features that are based on the distance-weighted means of surrounding spatial locations. + +```{python} +import geopandas as gpd +import numpy as np +from tempfile import NamedTemporaryFile +from pyspatialml import Raster +import pyspatialml.datasets.meuse as ms +import matplotlib as mpl +import matplotlib.pyplot as plt +``` + +## Preparing the Raster Predictors + +Import the raster predictors from the `pyspatialml.datasets.meuse` module: + +```{python} +predictor_files = ms.predictors +training_pts_file = ms.meuse +stack = Raster(predictor_files) +stack.drop('ffreq') +``` + +In order to generate new features from surrounding spatial locations, we need their x,y coordinates, which will will add to the stack of the raster predictors using the `pyspatialml.preprocessing.xy_coordinates` function: + +```{python} +from pyspatialml.preprocessing import xy_coordinates + +xy_layers = xy_coordinates(stack.iloc[0], NamedTemporaryFile(suffix=".tif").name) +stack = stack.append(xy_layers, in_place=False) +``` + +Quickly plot the raster predictors: + +```{python} +mpl.style.use('seaborn-v0_8') +axs = stack.plot(figsize=(9, 7)) +ax = axs.flatten()[10] +im = ax.images +im[0].colorbar.set_ticks([1,2,3]) +ax = axs.flatten()[8] +ax.tick_params(axis='x', labelrotation=65) + +plt.tight_layout() +plt.show() +``` + +## Extract the Training Data + +Spatially query the raster predictors at the training point locations: + +```{python} +training_pts = gpd.read_file(training_pts_file) +training_df = stack.extract_vector(gdf=training_pts) + +training_df.index = training_df.index.get_level_values("geometry_idx") +training_df = training_df.merge( + training_pts.loc[:, ("lead", "cadmium", "copper", "zinc", "om")], + left_index=True, + right_index=True +) +training_df = training_df.dropna() +``` + +Split the response/target variables from the predictors: + +```{python} +X = training_df.loc[:, stack.names].values +y = training_df.loc[:, ['lead', 'cadmium', 'copper', 'zinc', 'om']].values +``` + +## Develop a Spatially-Lagged Machine Learning Model + +As well as using the ExtraTreeRegressor model which was also used in example 1, here we will use the custom `pyspatialml.estimators.SpatialLagRegressor` metalearner class to wrap the extratrees regressor into a model that adds a new feature based on the distance-weighted mean of spatially-proximal observations: + +```{python} +from sklearn.pipeline import Pipeline +from sklearn.ensemble import ExtraTreesRegressor +from sklearn.preprocessing import OneHotEncoder +from sklearn.compose import ColumnTransformer +from pyspatialml.transformers import KNNTransformer +from sklearn.model_selection import cross_validate, KFold +from sklearn.model_selection import GridSearchCV + +# define regressor +et = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=1234) + +soil_index = list(stack.names).index("soil") +xy_indexes = [list(stack.names).index(i) for i in ["x_coordinates", "y_coordinates"]] + +preproc = ColumnTransformer([ + ('ohe', OneHotEncoder(categories='auto', handle_unknown='ignore'), [soil_index]), + ('lags', KNNTransformer(weights='distance', measure="mean"), xy_indexes) +], remainder='passthrough') + +wflow = Pipeline([ + ('preproc', preproc), + ('regressor', et) +]) + +search_grid = {"preproc__lags__n_neighbors": [3, 5, 7, 9]} +inner = KFold(n_splits=3, shuffle=True, random_state=1234) +model = GridSearchCV(wflow, param_grid=search_grid, cv=inner, scoring="r2") +``` + +Fit the model and cross-validate: + +```{python} +model = model.fit(X, y) +model.best_params_ +``` + +```{python} +outer = KFold(n_splits=10, shuffle=True, random_state=1234) + +scores = cross_validate(model, X, y, scoring='neg_mean_squared_error', cv=outer, n_jobs=1) +rmse = np.sqrt(-scores['test_score']).mean() + +print("Our RMSE score is {}".format(rmse)) +``` + +Comparing the RMSE score the the score obtained in example 1, where the spatial structure of the training data was accounted for indirectly by added a variety of raster distance measures, we can see that the RMSE score is slightly improved. + +## Multi-Target Predictions + +```{python} +preds = stack.predict(model) +preds.rename( + {old: new for old, new in zip(preds.names, ['lead', 'cadmium', 'copper', 'zinc', 'om'])}, + in_place=True +) +preds.lead.cmap = 'rainbow' +preds.cadmium.cmap = 'rainbow' +preds.copper.cmap = 'rainbow' +preds.zinc.cmap = 'rainbow' +preds.om.cmap = 'rainbow' +``` + +```{python} +preds.plot(out_shape=(200, 200), title_fontsize=14, figsize=(10, 8)) +plt.show() +``` + diff --git a/docs/transformers.qmd b/docs/transformers.qmd index f92faed..8f4f9d6 100644 --- a/docs/transformers.qmd +++ b/docs/transformers.qmd @@ -1,67 +1,67 @@ ---- -title: "Transformers" -format: - html: - code-fold: false - toc: true -jupyter: python3 ---- - -The transformers module contains classes that are used for spatial feature engineering. - -## Spatial Lag Transformer - -A transformer to create spatial lag variables by using a -weighted mean/mode of the values of the K-neighboring observations. The -weighted mean/mode of the surrounding observations are appended as a new -feature to the right-most column in the training data. The `measure` parameter -should be set to 'mode' for classification, and 'mean' for regression. - -``` -KNNTransformer( - n_neighbors=7, - weights="distance", - measure="mean", - radius=1.0, - algorithm="auto", - leaf_size=30, - metric="minkowski", - p=2, - normalize=True, - metric_params=None, - kernel_params=None, - n_jobs=1 -) -``` - -## GeoDistTransformer - -A common spatial feature engineering task is to create new features that -describe the proximity to some reference locations. The GeoDistTransformer -can be used to add these features as part of a machine learning pipeline. - -``` -GeoDistTransformer(refs, log=False) -``` - -Where `refs` are an array of coordinates of reference locations in -(m, n-dimensional) order, such as -{n_locations, x_coordinates, y_coordinates, ...} for as many dimensions as -required. For example to calculate distances to a single x,y,z location: - -``` -refs = [-57.345, -110.134, 1012] -``` - -And to calculate distances to three x,y reference locations: - -``` -refs = [ - [-57.345, -110.134], - [-56.345, -109.123], - [-58.534, -112.123] -] -``` - -The supplied array has to have at least x,y coordinates with a -(1, 2) shape for a single location. +--- +title: "Transformers" +format: + html: + code-fold: false + toc: true +jupyter: python3 +--- + +The transformers module contains classes that are used for spatial feature engineering. + +## Spatial Lag Transformer + +A transformer to create spatial lag variables by using a +weighted mean/mode of the values of the K-neighboring observations. The +weighted mean/mode of the surrounding observations are appended as a new +feature to the right-most column in the training data. The `measure` parameter +should be set to 'mode' for classification, and 'mean' for regression. + +``` +KNNTransformer( + n_neighbors=7, + weights="distance", + measure="mean", + radius=1.0, + algorithm="auto", + leaf_size=30, + metric="minkowski", + p=2, + normalize=True, + metric_params=None, + kernel_params=None, + n_jobs=1 +) +``` + +## GeoDistTransformer + +A common spatial feature engineering task is to create new features that +describe the proximity to some reference locations. The GeoDistTransformer +can be used to add these features as part of a machine learning pipeline. + +``` +GeoDistTransformer(refs, log=False) +``` + +Where `refs` are an array of coordinates of reference locations in +(m, n-dimensional) order, such as +{n_locations, x_coordinates, y_coordinates, ...} for as many dimensions as +required. For example to calculate distances to a single x,y,z location: + +``` +refs = [-57.345, -110.134, 1012] +``` + +And to calculate distances to three x,y reference locations: + +``` +refs = [ + [-57.345, -110.134], + [-56.345, -109.123], + [-58.534, -112.123] +] +``` + +The supplied array has to have at least x,y coordinates with a +(1, 2) shape for a single location. diff --git a/docs/usage.qmd b/docs/usage.qmd index 6c949c8..80843d8 100644 --- a/docs/usage.qmd +++ b/docs/usage.qmd @@ -1,32 +1,32 @@ ---- -title: "Usage" -format: html ---- - -## The Raster class - -The main approach to working with raster datasets in Pyspatialml is through the `Raster` class. The `Raster` object takes a list of GDAL-supported raster datasets and references them as part of a single Raster object, which can be used to perform operations on the raster datasets as a whole. The `Raster` object is a thin wrapper around the `rasterio` library, which is a Python library for reading and writing raster datasets. The individual bands within the datasets are represented internally as `RasterLayer` objects. This allows for retaining metadata about each raster dataset and adding or removing raster datasets from the stack without making physical changes to the disk. - -Note that in order to initiate a Raster object, the underlying raster datasets must be spatially aligned in terms of their extent, resolution, and coordinate reference system - Raster objects do not perform any resampling or reprojection of the underlying datasets. Functions within the `preprocessing` module can be used to align raster datasets before creating a Raster object. - -### Creating a Raster - -The most common approach of initiating a Raster object is from an existing raster dataset, or a list of raster datasets. Alternatively, a Raster object can also be initiated from a 3D numpy array: - -- ``Raster(src=[raster1.tif, raster2.tif, raster3.tif])`` creates a Raster object from existing file-based GDAL-supported datasets, or a single raster dataset. The file-based datasets can contain single or multiple bands. - -- ``Raster(src=new_numpy_array, crs=crs, transform=transform)`` creates a Raster object from a 3D numpy array (band, row, column). The ``crs`` and ``transform`` arguments are optional but are required to provide coordinate reference system information to the Raster object. The crs argument has to be represented by ```rasterio crs.CRS``` object, and the transform parameter requires an ```affine.Affine``` object. - -Rasters can also be initated directly from a `rasterio.Band` object(s), or from a list of `RasterLayer` objects (see below). - -### RasterLayers - -Generally, Pyspatialml intends users to work with the Raster object. However, internally, the Raster object is composed of RasterLayer objects, which represent individual bands of a raster dataset. RasterLayers are based on a ``rasterio.band`` object with some additional attributes and methods. However, unlike the `rasterio.Band.ds.read` method which reads all bands within a multi-band dataset, the RasterLayer read method always refers to a single band. - -Methods contained within RasterLayer objects are specifically designed to be applied to individual bands of a raster. These methods include operations such as sieve-clump, distance to non-NaN pixels, and arithmetic operations on individual layers. - -## Principles of working with Rasters - -Methods that are applied to Raster objects are generally designed to be applied to the entire stack of raster datasets. For example, the `crop` method will crop all raster datasets in the stack to a common extent, and the `mask` method will apply a mask to all raster datasets in the stack. These methods always return a new Raster object, and do not modify the original Raster object by default. Subsetting of individual bands uses the same principles as the `pandas` library, where the `loc` method is used to subset bands based on their names, and the `iloc` method is used to subset bands based on their index. Also similarly to `pandas`, subsetting a single band will return the object itself, in this case, a RasterLayer object, while subsetting multiple bands will return a new Raster object. - -Methods that apply to individual RasterLayers are mostly related to extracting or summarizing metadata from the individual bands. For other methods that users may want to apply to individual bands, it is recommended to work with `rasterio` directly. +--- +title: "Usage" +format: html +--- + +## The Raster class + +The main approach to working with raster datasets in Pyspatialml is through the `Raster` class. The `Raster` object takes a list of GDAL-supported raster datasets and references them as part of a single Raster object, which can be used to perform operations on the raster datasets as a whole. The `Raster` object is a thin wrapper around the `rasterio` library, which is a Python library for reading and writing raster datasets. The individual bands within the datasets are represented internally as `RasterLayer` objects. This allows for retaining metadata about each raster dataset and adding or removing raster datasets from the stack without making physical changes to the disk. + +Note that in order to initiate a Raster object, the underlying raster datasets must be spatially aligned in terms of their extent, resolution, and coordinate reference system - Raster objects do not perform any resampling or reprojection of the underlying datasets. Functions within the `preprocessing` module can be used to align raster datasets before creating a Raster object. + +### Creating a Raster + +The most common approach of initiating a Raster object is from an existing raster dataset, or a list of raster datasets. Alternatively, a Raster object can also be initiated from a 3D numpy array: + +- ``Raster(src=[raster1.tif, raster2.tif, raster3.tif])`` creates a Raster object from existing file-based GDAL-supported datasets, or a single raster dataset. The file-based datasets can contain single or multiple bands. + +- ``Raster(src=new_numpy_array, crs=crs, transform=transform)`` creates a Raster object from a 3D numpy array (band, row, column). The ``crs`` and ``transform`` arguments are optional but are required to provide coordinate reference system information to the Raster object. The crs argument has to be represented by ```rasterio crs.CRS``` object, and the transform parameter requires an ```affine.Affine``` object. + +Rasters can also be initated directly from a `rasterio.Band` object(s), or from a list of `RasterLayer` objects (see below). + +### RasterLayers + +Generally, Pyspatialml intends users to work with the Raster object. However, internally, the Raster object is composed of RasterLayer objects, which represent individual bands of a raster dataset. RasterLayers are based on a ``rasterio.band`` object with some additional attributes and methods. However, unlike the `rasterio.Band.ds.read` method which reads all bands within a multi-band dataset, the RasterLayer read method always refers to a single band. + +Methods contained within RasterLayer objects are specifically designed to be applied to individual bands of a raster. These methods include operations such as sieve-clump, distance to non-NaN pixels, and arithmetic operations on individual layers. + +## Principles of working with Rasters + +Methods that are applied to Raster objects are generally designed to be applied to the entire stack of raster datasets. For example, the `crop` method will crop all raster datasets in the stack to a common extent, and the `mask` method will apply a mask to all raster datasets in the stack. These methods always return a new Raster object, and do not modify the original Raster object by default. Subsetting of individual bands uses the same principles as the `pandas` library, where the `loc` method is used to subset bands based on their names, and the `iloc` method is used to subset bands based on their index. Also similarly to `pandas`, subsetting a single band will return the object itself, in this case, a RasterLayer object, while subsetting multiple bands will return a new Raster object. + +Methods that apply to individual RasterLayers are mostly related to extracting or summarizing metadata from the individual bands. For other methods that users may want to apply to individual bands, it is recommended to work with `rasterio` directly. diff --git a/index.qmd b/index.qmd index 775313d..947a845 100644 --- a/index.qmd +++ b/index.qmd @@ -1,55 +1,55 @@ ---- -title: "Overview" -format: html ---- - -Pyspatialml is a Python package for applying scikit-learn machine learning -models to raster-based datasets. It is inspired by the famous -[raster](https://cran.r-project.org/web/packages/raster/index.html) -package in the R statistical programming language which has been extensively -used for applying statistical and machine learning models to geospatial raster -datasets. - -Pyspatialml includes functions and classes for working with multiple raster -datasets and applying typical machine learning workflows including raster data -manipulation, feature engineering on raster datasets, extraction of training -data, and application of the ``predict`` or ``predict_proba`` methods of -scikit-learn estimator objects to a stack of raster datasets. - -Pyspatialml is built upon the -[rasterio](https://rasterio.readthedocs.io/en/latest/) Python package which -performs all of the heavy lifting and is designed to work with the -[geopandas](https://geopandas.org) package for related raster-vector data -geoprocessing operations. - -## Purpose - -A supervised machine-learning workflow as applied to spatial raster data -typically involves several steps: - -1. Using vector features or labelled pixels to extract training data from a - stack of raster-based predictors (e.g. spectral bands, terrain derivatives, - or climate grids). The training data represent locations when some - property/state/concentration is already established, and might comprise - point locations of arsenic concentrations, or labelled pixels with - integer-encoded values that correspond to known landcover types. - -2. Developing a machine learning classification or regression model on the - training data. Pyspatialml is designed to use scikit-learn compatible api's - for this purpose. -3. Applying the fitted machine learning model to make predictions on all of - the pixels in the stack of raster data. - -Pyspatialml is designed to make it easy to develop spatial prediction models on -stacks of 2D raster datasets that are held on disk. Unlike using python's -``numpy`` module directly where raster datasets need to be held in memory, the -majority of functions within pyspatialml work with raster datasets that are -stored on disk and allow processing operations to be performed on datasets that -are too large to be loaded into memory. - -Pyspatialml is designed to make it easy to work with typical raster data stacks -consisting of multiple 2D grids such as different spectal bands, maps etc. -However, it's purpose is not to work with multidimensional datasets, i.e. those -that have more than 3 dimensions such as spacetime cubes of multiband data. The -[xarray](http://xarray.pydata.org/en/stable/index.html) package can provide a -structure for this type of data. +--- +title: "Overview" +format: html +--- + +Pyspatialml is a Python package for applying scikit-learn machine learning +models to raster-based datasets. It is inspired by the famous +[raster](https://cran.r-project.org/web/packages/raster/index.html) +package in the R statistical programming language which has been extensively +used for applying statistical and machine learning models to geospatial raster +datasets. + +Pyspatialml includes functions and classes for working with multiple raster +datasets and applying typical machine learning workflows including raster data +manipulation, feature engineering on raster datasets, extraction of training +data, and application of the ``predict`` or ``predict_proba`` methods of +scikit-learn estimator objects to a stack of raster datasets. + +Pyspatialml is built upon the +[rasterio](https://rasterio.readthedocs.io/en/latest/) Python package which +performs all of the heavy lifting and is designed to work with the +[geopandas](https://geopandas.org) package for related raster-vector data +geoprocessing operations. + +## Purpose + +A supervised machine-learning workflow as applied to spatial raster data +typically involves several steps: + +1. Using vector features or labelled pixels to extract training data from a + stack of raster-based predictors (e.g. spectral bands, terrain derivatives, + or climate grids). The training data represent locations when some + property/state/concentration is already established, and might comprise + point locations of arsenic concentrations, or labelled pixels with + integer-encoded values that correspond to known landcover types. + +2. Developing a machine learning classification or regression model on the + training data. Pyspatialml is designed to use scikit-learn compatible api's + for this purpose. +3. Applying the fitted machine learning model to make predictions on all of + the pixels in the stack of raster data. + +Pyspatialml is designed to make it easy to develop spatial prediction models on +stacks of 2D raster datasets that are held on disk. Unlike using python's +``numpy`` module directly where raster datasets need to be held in memory, the +majority of functions within pyspatialml work with raster datasets that are +stored on disk and allow processing operations to be performed on datasets that +are too large to be loaded into memory. + +Pyspatialml is designed to make it easy to work with typical raster data stacks +consisting of multiple 2D grids such as different spectal bands, maps etc. +However, it's purpose is not to work with multidimensional datasets, i.e. those +that have more than 3 dimensions such as spacetime cubes of multiband data. The +[xarray](http://xarray.pydata.org/en/stable/index.html) package can provide a +structure for this type of data. diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index a8da50b..0000000 --- a/poetry.lock +++ /dev/null @@ -1,3756 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. - -[[package]] -name = "affine" -version = "2.4.0" -description = "Matrices describing affine transformation of the plane" -optional = false -python-versions = ">=3.7" -files = [ - {file = "affine-2.4.0-py3-none-any.whl", hash = "sha256:8a3df80e2b2378aef598a83c1392efd47967afec4242021a0b06b4c7cbc61a92"}, - {file = "affine-2.4.0.tar.gz", hash = "sha256:a24d818d6a836c131976d22f8c27b8d3ca32d0af64c1d8d29deb7bafa4da1eea"}, -] - -[package.extras] -dev = ["coveralls", "flake8", "pydocstyle"] -test = ["pytest (>=4.6)", "pytest-cov"] - -[[package]] -name = "annotated-types" -version = "0.6.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, -] - -[[package]] -name = "anyio" -version = "4.3.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, -] - -[package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} -idna = ">=2.8" -sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] - -[[package]] -name = "appnope" -version = "0.1.4" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = ">=3.6" -files = [ - {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, - {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, -] - -[[package]] -name = "argon2-cffi" -version = "23.1.0" -description = "Argon2 for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, - {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, -] - -[package.dependencies] -argon2-cffi-bindings = "*" - -[package.extras] -dev = ["argon2-cffi[tests,typing]", "tox (>4)"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] -tests = ["hypothesis", "pytest"] -typing = ["mypy"] - -[[package]] -name = "argon2-cffi-bindings" -version = "21.2.0" -description = "Low-level CFFI bindings for Argon2" -optional = false -python-versions = ">=3.6" -files = [ - {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, - {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, -] - -[package.dependencies] -cffi = ">=1.0.1" - -[package.extras] -dev = ["cogapp", "pre-commit", "pytest", "wheel"] -tests = ["pytest"] - -[[package]] -name = "arrow" -version = "1.3.0" -description = "Better dates & times for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, - {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, -] - -[package.dependencies] -python-dateutil = ">=2.7.0" -types-python-dateutil = ">=2.8.10" - -[package.extras] -doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] -test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] - -[[package]] -name = "asttokens" -version = "2.4.1" -description = "Annotate AST trees with source code positions" -optional = false -python-versions = "*" -files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, -] - -[package.dependencies] -six = ">=1.12.0" - -[package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] - -[[package]] -name = "async-lru" -version = "2.0.4" -description = "Simple LRU cache for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"}, - {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "attrs" -version = "23.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"}, -] - -[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]"] - -[[package]] -name = "babel" -version = "2.15.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, -] - -[package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] - -[[package]] -name = "beartype" -version = "0.18.5" -description = "Unbearably fast runtime type checking in pure Python." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "beartype-0.18.5-py3-none-any.whl", hash = "sha256:5301a14f2a9a5540fe47ec6d34d758e9cd8331d36c4760fc7a5499ab86310089"}, - {file = "beartype-0.18.5.tar.gz", hash = "sha256:264ddc2f1da9ec94ff639141fbe33d22e12a9f75aa863b83b7046ffff1381927"}, -] - -[package.extras] -all = ["typing-extensions (>=3.10.0.0)"] -dev = ["autoapi (>=0.9.0)", "coverage (>=5.5)", "equinox", "mypy (>=0.800)", "numpy", "pandera", "pydata-sphinx-theme (<=0.7.2)", "pytest (>=4.0.0)", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "tox (>=3.20.1)", "typing-extensions (>=3.10.0.0)"] -doc-rtd = ["autoapi (>=0.9.0)", "pydata-sphinx-theme (<=0.7.2)", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)"] -test-tox = ["equinox", "mypy (>=0.800)", "numpy", "pandera", "pytest (>=4.0.0)", "sphinx", "typing-extensions (>=3.10.0.0)"] -test-tox-coverage = ["coverage (>=5.5)"] - -[[package]] -name = "beautifulsoup4" -version = "4.12.3" -description = "Screen-scraping library" -optional = false -python-versions = ">=3.6.0" -files = [ - {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, - {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, -] - -[package.dependencies] -soupsieve = ">1.2" - -[package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "black" -version = "24.4.2" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "bleach" -version = "6.1.0" -description = "An easy safelist-based HTML-sanitizing tool." -optional = false -python-versions = ">=3.8" -files = [ - {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, - {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, -] - -[package.dependencies] -six = ">=1.9.0" -webencodings = "*" - -[package.extras] -css = ["tinycss2 (>=1.1.0,<1.3)"] - -[[package]] -name = "certifi" -version = "2024.7.4" -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"}, -] - -[[package]] -name = "cffi" -version = "1.16.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "click-plugins" -version = "1.1.1" -description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -optional = false -python-versions = "*" -files = [ - {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, - {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] - -[[package]] -name = "cligj" -version = "0.7.2" -description = "Click params for commmand line interfaces to GeoJSON" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" -files = [ - {file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"}, - {file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -test = ["pytest-cov"] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "comm" -version = "0.2.2" -description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -optional = false -python-versions = ">=3.8" -files = [ - {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, - {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, -] - -[package.dependencies] -traitlets = ">=4" - -[package.extras] -test = ["pytest"] - -[[package]] -name = "contourpy" -version = "1.2.1" -description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false -python-versions = ">=3.9" -files = [ - {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, - {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, - {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, - {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, - {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, - {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, - {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, - {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, - {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, - {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, - {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, -] - -[package.dependencies] -numpy = ">=1.20" - -[package.extras] -bokeh = ["bokeh", "selenium"] -docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] -test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] - -[[package]] -name = "coverage" -version = "7.5.3" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, - {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, - {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, - {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, - {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, - {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, - {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, - {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, - {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, - {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, - {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, - {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, - {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, - {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, -] - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "cycler" -version = "0.12.1" -description = "Composable style cycles" -optional = false -python-versions = ">=3.8" -files = [ - {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, - {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, -] - -[package.extras] -docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] -tests = ["pytest", "pytest-cov", "pytest-xdist"] - -[[package]] -name = "debugpy" -version = "1.8.1" -description = "An implementation of the Debug Adapter Protocol for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, -] - -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.5" -files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -description = "XML bomb protection for Python stdlib modules" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.2.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "executing" -version = "2.0.1" -description = "Get the currently executing AST node of a frame, and other information" -optional = false -python-versions = ">=3.5" -files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, -] - -[package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] - -[[package]] -name = "fastjsonschema" -version = "2.19.1" -description = "Fastest Python implementation of JSON schema" -optional = false -python-versions = "*" -files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, -] - -[package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] - -[[package]] -name = "fiona" -version = "1.10.0" -description = "Fiona reads and writes spatial data files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fiona-1.10.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2f8c6e7d2e5e2dc3b72b520cd160ca6d3689748b20d35b518eec9073f5a3c5bf"}, - {file = "fiona-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2a42fb0a7168003015ab9648712f7d7eb971237af3c9be6000df69cd4b97ba7"}, - {file = "fiona-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d95a93d6d37e04232b141d9f08190b30e7dc368126a34342d764b9d0a857d770"}, - {file = "fiona-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:382cffc905d44a933951857ae07f79cf59567db08f4201ed2a28f9f9bcc86932"}, - {file = "fiona-1.10.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:2854fca6478ca3c1dc3f06531025550046f405488909a5be11ea97e4c55894db"}, - {file = "fiona-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef27d75046e57b3e55c4b5d4e1bf7e43ef490e73ada5e86f9b148aa23a2e7fd4"}, - {file = "fiona-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16072f9313f60220310951561c5df29122d078d26316455dc58516c330881d35"}, - {file = "fiona-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a7f28c5667d5cb05891fd00ed8ca2d3067bb58c90ca928a2741c0da74daf10d"}, - {file = "fiona-1.10.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:d099b1b5ab99db1d144ac47f657e14471178537d878ebd016c37afdf37303399"}, - {file = "fiona-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ad1ea80555bc56047d4b4e60c9424cf66875f161b3e56ebd60fa0574dc6693f"}, - {file = "fiona-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a273cc957e86289609b47155f75d60c2cc37974a92618e016f75bc5ab9cc2dec"}, - {file = "fiona-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:ef44b3b0704244503a5f12ae92ca88b2cf4fedc9fd881b00c7c58b6899ca5133"}, - {file = "fiona-1.10.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:80929d220a92b50592b5ce96233d631c61a3c9b9bebd26ea136e7e48ffb50616"}, - {file = "fiona-1.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82514e8cc113245f2c7deda1c66f0aba67b183e20404365bbb7347e12b35c80f"}, - {file = "fiona-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1a555b2546d3c69d0826a526a5c3e50a1cd330c95e2e0ebf6e82fa81fc2d96"}, - {file = "fiona-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:bf11de868ab601b8d917dc38719b39bf8bdeaadc4fda9964d96b4b354e528fff"}, - {file = "fiona-1.10.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:c0e72c4ed6ce7e2b2531a62844f3216528c149b55b89ff2881bcfe34d3b37300"}, - {file = "fiona-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:065328fcc61caeca7c5d4b0b1b741213e422997ea66eaa04c2e207e1609eb0e7"}, - {file = "fiona-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34575acb68b41009b28237121c728015aebb2ab3969cf46e57d9b9e5510ece61"}, - {file = "fiona-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:bfc9b76345a58ddcf9aae8697eb444728ff7a2cde7d5925f3031ff25e9eaa339"}, - {file = "fiona-1.10.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f335beb927c5e9d9997a9cf665d6eee2e24191a02582f01786afa76119b71110"}, - {file = "fiona-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5f1db6fc3f9212fdc817628981731e0adcdce88b0afd30531986c732a75f6a98"}, - {file = "fiona-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc68efb479a04be9a8e9c381940493c22a47f6aec5bbec22d0bb57a9cb240296"}, - {file = "fiona-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:d99d2faa8cb3590dc0018a2832af39e1930b39cfff53017f3681d505bf813fee"}, - {file = "fiona-1.10.0.tar.gz", hash = "sha256:3529fd46d269ff3f70aeb9316a93ae95cf2f87d7e148a8ff0d68532bf81ff7ae"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -certifi = "*" -click = ">=8.0,<9.0" -click-plugins = ">=1.0" -cligj = ">=0.5" -importlib-metadata = {version = "*", markers = "python_version < \"3.10\""} - -[package.extras] -all = ["fiona[calc,s3,test]"] -calc = ["pyparsing", "shapely"] -s3 = ["boto3 (>=1.3.1)"] -test = ["aiohttp", "fiona[s3]", "fsspec", "pytest (>=7)", "pytest-cov", "pytz"] - -[[package]] -name = "fonttools" -version = "4.51.0" -description = "Tools to manipulate font files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"}, - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"}, - {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"}, - {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"}, - {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"}, - {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"}, - {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"}, - {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"}, - {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"}, - {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"}, - {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"}, - {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"}, - {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"}, - {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"}, -] - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] -graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0)"] -pathops = ["skia-pathops (>=0.5.0)"] -plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] -symfont = ["sympy"] -type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.1.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] - -[[package]] -name = "fqdn" -version = "1.5.1" -description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" -optional = false -python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" -files = [ - {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, - {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, -] - -[[package]] -name = "geopandas" -version = "0.14.4" -description = "Geographic pandas extensions" -optional = false -python-versions = ">=3.9" -files = [ - {file = "geopandas-0.14.4-py3-none-any.whl", hash = "sha256:3bb6473cb59d51e1a7fe2dbc24a1a063fb0ebdeddf3ce08ddbf8c7ddc99689aa"}, - {file = "geopandas-0.14.4.tar.gz", hash = "sha256:56765be9d58e2c743078085db3bd07dc6be7719f0dbe1dfdc1d705cb80be7c25"}, -] - -[package.dependencies] -fiona = ">=1.8.21" -numpy = ">=1.22" -packaging = "*" -pandas = ">=1.4.0" -pyproj = ">=3.3.0" -shapely = ">=1.8.0" - -[[package]] -name = "griffe" -version = "0.45.1" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.8" -files = [ - {file = "griffe-0.45.1-py3-none-any.whl", hash = "sha256:12194c10ae07a7f46708741ad78419362cf8e5c883f449c7c48de1686611b853"}, - {file = "griffe-0.45.1.tar.gz", hash = "sha256:84ce9243a9e63c07d55563a735a0d07ef70b46c455616c174010e7fc816f4648"}, -] - -[package.dependencies] -colorama = ">=0.4" - -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "httpcore" -version = "1.0.5" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] - -[[package]] -name = "httpx" -version = "0.27.0" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] - -[[package]] -name = "idna" -version = "3.7" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, -] - -[[package]] -name = "importlib-metadata" -version = "7.1.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, -] - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["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)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "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.4.0" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, -] - -[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 = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "ipykernel" -version = "6.29.4" -description = "IPython Kernel for Jupyter" -optional = false -python-versions = ">=3.8" -files = [ - {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, - {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, -] - -[package.dependencies] -appnope = {version = "*", markers = "platform_system == \"Darwin\""} -comm = ">=0.1.1" -debugpy = ">=1.6.5" -ipython = ">=7.23.1" -jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -matplotlib-inline = ">=0.1" -nest-asyncio = "*" -packaging = "*" -psutil = "*" -pyzmq = ">=24" -tornado = ">=6.1" -traitlets = ">=5.4.0" - -[package.extras] -cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] -pyqt5 = ["pyqt5"] -pyside6 = ["pyside6"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "ipython" -version = "8.18.1" -description = "IPython: Productive Interactive Computing" -optional = false -python-versions = ">=3.9" -files = [ - {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, - {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -prompt-toolkit = ">=3.0.41,<3.1.0" -pygments = ">=2.4.0" -stack-data = "*" -traitlets = ">=5" -typing-extensions = {version = "*", markers = "python_version < \"3.10\""} - -[package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] -black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] -kernel = ["ipykernel"] -nbconvert = ["nbconvert"] -nbformat = ["nbformat"] -notebook = ["ipywidgets", "notebook"] -parallel = ["ipyparallel"] -qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] - -[[package]] -name = "ipywidgets" -version = "8.1.2" -description = "Jupyter interactive widgets" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, - {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, -] - -[package.dependencies] -comm = ">=0.1.3" -ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.10,<3.1.0" -traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.10,<4.1.0" - -[package.extras] -test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] - -[[package]] -name = "isoduration" -version = "20.11.0" -description = "Operations with ISO 8601 durations" -optional = false -python-versions = ">=3.7" -files = [ - {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, - {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, -] - -[package.dependencies] -arrow = ">=0.15.0" - -[[package]] -name = "jedi" -version = "0.19.1" -description = "An autocompletion tool for Python that can be used for text editors." -optional = false -python-versions = ">=3.6" -files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, -] - -[package.dependencies] -parso = ">=0.8.3,<0.9.0" - -[package.extras] -docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] - -[[package]] -name = "jinja2" -version = "3.1.4" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "joblib" -version = "1.4.2" -description = "Lightweight pipelining with Python functions" -optional = false -python-versions = ">=3.8" -files = [ - {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, - {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, -] - -[[package]] -name = "json5" -version = "0.9.25" -description = "A Python implementation of the JSON5 data format." -optional = false -python-versions = ">=3.8" -files = [ - {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"}, - {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"}, -] - -[[package]] -name = "jsonpointer" -version = "2.4" -description = "Identify specific nodes in a JSON document (RFC 6901)" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" -files = [ - {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, - {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, -] - -[[package]] -name = "jsonschema" -version = "4.22.0" -description = "An implementation of JSON Schema validation for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, - {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -fqdn = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -idna = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -isoduration = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -jsonpointer = {version = ">1.13", optional = true, markers = "extra == \"format-nongpl\""} -jsonschema-specifications = ">=2023.03.6" -referencing = ">=0.28.4" -rfc3339-validator = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} -rpds-py = ">=0.7.1" -uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} - -[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)"] - -[[package]] -name = "jsonschema-specifications" -version = "2023.12.1" -description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, -] - -[package.dependencies] -referencing = ">=0.31.0" - -[[package]] -name = "jupyter" -version = "1.0.0" -description = "Jupyter metapackage. Install all the Jupyter components in one go." -optional = false -python-versions = "*" -files = [ - {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, - {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, - {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, -] - -[package.dependencies] -ipykernel = "*" -ipywidgets = "*" -jupyter-console = "*" -nbconvert = "*" -notebook = "*" -qtconsole = "*" - -[[package]] -name = "jupyter-client" -version = "8.6.1" -description = "Jupyter protocol implementation and client libraries" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, - {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -python-dateutil = ">=2.8.2" -pyzmq = ">=23.0" -tornado = ">=6.2" -traitlets = ">=5.3" - -[package.extras] -docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] - -[[package]] -name = "jupyter-console" -version = "6.6.3" -description = "Jupyter terminal console" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"}, - {file = "jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539"}, -] - -[package.dependencies] -ipykernel = ">=6.14" -ipython = "*" -jupyter-client = ">=7.0.0" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -prompt-toolkit = ">=3.0.30" -pygments = "*" -pyzmq = ">=17" -traitlets = ">=5.4" - -[package.extras] -test = ["flaky", "pexpect", "pytest"] - -[[package]] -name = "jupyter-core" -version = "5.7.2" -description = "Jupyter core package. A base package on which Jupyter projects rely." -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, - {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, -] - -[package.dependencies] -platformdirs = ">=2.5" -pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} -traitlets = ">=5.3" - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "jupyter-events" -version = "0.10.0" -description = "Jupyter Event System library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, - {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, -] - -[package.dependencies] -jsonschema = {version = ">=4.18.0", extras = ["format-nongpl"]} -python-json-logger = ">=2.0.4" -pyyaml = ">=5.3" -referencing = "*" -rfc3339-validator = "*" -rfc3986-validator = ">=0.1.1" -traitlets = ">=5.3" - -[package.extras] -cli = ["click", "rich"] -docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] -test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] - -[[package]] -name = "jupyter-lsp" -version = "2.2.5" -description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001"}, - {file = "jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -jupyter-server = ">=1.1.2" - -[[package]] -name = "jupyter-server" -version = "2.14.0" -description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter_server-2.14.0-py3-none-any.whl", hash = "sha256:fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210"}, - {file = "jupyter_server-2.14.0.tar.gz", hash = "sha256:659154cea512083434fd7c93b7fe0897af7a2fd0b9dd4749282b42eaac4ae677"}, -] - -[package.dependencies] -anyio = ">=3.1.0" -argon2-cffi = ">=21.1" -jinja2 = ">=3.0.3" -jupyter-client = ">=7.4.4" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -jupyter-events = ">=0.9.0" -jupyter-server-terminals = ">=0.4.4" -nbconvert = ">=6.4.4" -nbformat = ">=5.3.0" -overrides = ">=5.0" -packaging = ">=22.0" -prometheus-client = ">=0.9" -pywinpty = {version = ">=2.0.1", markers = "os_name == \"nt\""} -pyzmq = ">=24" -send2trash = ">=1.8.2" -terminado = ">=0.8.3" -tornado = ">=6.2.0" -traitlets = ">=5.6.0" -websocket-client = ">=1.7" - -[package.extras] -docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] -test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] - -[[package]] -name = "jupyter-server-terminals" -version = "0.5.3" -description = "A Jupyter Server Extension Providing Terminals." -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"}, - {file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"}, -] - -[package.dependencies] -pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} -terminado = ">=0.8.3" - -[package.extras] -docs = ["jinja2", "jupyter-server", "mistune (<4.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] -test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] - -[[package]] -name = "jupyterlab" -version = "4.2.5" -description = "JupyterLab computational environment" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyterlab-4.2.5-py3-none-any.whl", hash = "sha256:73b6e0775d41a9fee7ee756c80f58a6bed4040869ccc21411dc559818874d321"}, - {file = "jupyterlab-4.2.5.tar.gz", hash = "sha256:ae7f3a1b8cb88b4f55009ce79fa7c06f99d70cd63601ee4aa91815d054f46f75"}, -] - -[package.dependencies] -async-lru = ">=1.0.0" -httpx = ">=0.25.0" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -ipykernel = ">=6.5.0" -jinja2 = ">=3.0.3" -jupyter-core = "*" -jupyter-lsp = ">=2.0.0" -jupyter-server = ">=2.4.0,<3" -jupyterlab-server = ">=2.27.1,<3" -notebook-shim = ">=0.2" -packaging = "*" -setuptools = ">=40.1.0" -tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} -tornado = ">=6.2.0" -traitlets = "*" - -[package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.3.5)"] -docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] -test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] -upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] - -[[package]] -name = "jupyterlab-pygments" -version = "0.3.0" -description = "Pygments theme using JupyterLab CSS variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, - {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, -] - -[[package]] -name = "jupyterlab-server" -version = "2.27.1" -description = "A set of server components for JupyterLab and JupyterLab like applications." -optional = false -python-versions = ">=3.8" -files = [ - {file = "jupyterlab_server-2.27.1-py3-none-any.whl", hash = "sha256:f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75"}, - {file = "jupyterlab_server-2.27.1.tar.gz", hash = "sha256:097b5ac709b676c7284ac9c5e373f11930a561f52cd5a86e4fc7e5a9c8a8631d"}, -] - -[package.dependencies] -babel = ">=2.10" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -jinja2 = ">=3.0.3" -json5 = ">=0.9.0" -jsonschema = ">=4.18.0" -jupyter-server = ">=1.21,<3" -packaging = ">=21.3" -requests = ">=2.31" - -[package.extras] -docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] -openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] -test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] - -[[package]] -name = "jupyterlab-widgets" -version = "3.0.10" -description = "Jupyter interactive widgets for JupyterLab" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, - {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, -] - -[[package]] -name = "kiwisolver" -version = "1.4.5" -description = "A fast implementation of the Cassowary constraint solver" -optional = false -python-versions = ">=3.7" -files = [ - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, - {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -optional = false -python-versions = ">=3.8" -files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, -] - -[[package]] -name = "matplotlib" -version = "3.9.0" -description = "Python plotting package" -optional = false -python-versions = ">=3.9" -files = [ - {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, - {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, - {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, - {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, - {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, - {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, - {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, - {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, - {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, - {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, - {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, -] - -[package.dependencies] -contourpy = ">=1.0.1" -cycler = ">=0.10" -fonttools = ">=4.22.0" -importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} -kiwisolver = ">=1.3.1" -numpy = ">=1.23" -packaging = ">=20.0" -pillow = ">=8" -pyparsing = ">=2.3.1" -python-dateutil = ">=2.7" - -[package.extras] -dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] - -[[package]] -name = "matplotlib-inline" -version = "0.1.7" -description = "Inline Matplotlib backend for Jupyter" -optional = false -python-versions = ">=3.8" -files = [ - {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, - {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, -] - -[package.dependencies] -traitlets = "*" - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "mistune" -version = "3.0.2" -description = "A sane and fast Markdown parser with useful plugins and renderers" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, - {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nbclient" -version = "0.10.0" -description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, - {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, -] - -[package.dependencies] -jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -nbformat = ">=5.1" -traitlets = ">=5.4" - -[package.extras] -dev = ["pre-commit"] -docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] - -[[package]] -name = "nbconvert" -version = "7.16.4" -description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." -optional = false -python-versions = ">=3.8" -files = [ - {file = "nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3"}, - {file = "nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4"}, -] - -[package.dependencies] -beautifulsoup4 = "*" -bleach = "!=5.0.0" -defusedxml = "*" -importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} -jinja2 = ">=3.0" -jupyter-core = ">=4.7" -jupyterlab-pygments = "*" -markupsafe = ">=2.0" -mistune = ">=2.0.3,<4" -nbclient = ">=0.5.0" -nbformat = ">=5.7" -packaging = "*" -pandocfilters = ">=1.4.1" -pygments = ">=2.4.1" -tinycss2 = "*" -traitlets = ">=5.1" - -[package.extras] -all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] -docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] -qtpdf = ["pyqtwebengine (>=5.15)"] -qtpng = ["pyqtwebengine (>=5.15)"] -serve = ["tornado (>=6.1)"] -test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] -webpdf = ["playwright"] - -[[package]] -name = "nbformat" -version = "5.10.4" -description = "The Jupyter Notebook format" -optional = false -python-versions = ">=3.8" -files = [ - {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, - {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, -] - -[package.dependencies] -fastjsonschema = ">=2.15" -jsonschema = ">=2.6" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -traitlets = ">=5.1" - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["pep440", "pre-commit", "pytest", "testpath"] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -description = "Patch asyncio to allow nested event loops" -optional = false -python-versions = ">=3.5" -files = [ - {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, - {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, -] - -[[package]] -name = "notebook" -version = "7.2.2" -description = "Jupyter Notebook - A web-based notebook environment for interactive computing" -optional = false -python-versions = ">=3.8" -files = [ - {file = "notebook-7.2.2-py3-none-any.whl", hash = "sha256:c89264081f671bc02eec0ed470a627ed791b9156cad9285226b31611d3e9fe1c"}, - {file = "notebook-7.2.2.tar.gz", hash = "sha256:2ef07d4220421623ad3fe88118d687bc0450055570cdd160814a59cf3a1c516e"}, -] - -[package.dependencies] -jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.2.0,<4.3" -jupyterlab-server = ">=2.27.1,<3" -notebook-shim = ">=0.2,<0.3" -tornado = ">=6.2.0" - -[package.extras] -dev = ["hatch", "pre-commit"] -docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.27.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] - -[[package]] -name = "notebook-shim" -version = "0.2.4" -description = "A shim layer for notebook traits and config" -optional = false -python-versions = ">=3.7" -files = [ - {file = "notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"}, - {file = "notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb"}, -] - -[package.dependencies] -jupyter-server = ">=1.8,<3" - -[package.extras] -test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"] - -[[package]] -name = "numpy" -version = "1.26.4" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.9" -files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, -] - -[[package]] -name = "overrides" -version = "7.7.0" -description = "A decorator to automatically detect mismatch when overriding a method." -optional = false -python-versions = ">=3.6" -files = [ - {file = "overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"}, - {file = "overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a"}, -] - -[[package]] -name = "packaging" -version = "24.0" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, -] - -[[package]] -name = "pandas" -version = "2.2.2" -description = "Powerful data structures for data analysis, time series, and statistics" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, - {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, - {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"}, - {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"}, - {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"}, - {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"}, - {file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"}, - {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"}, - {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"}, - {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, - {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, - {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"}, - {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"}, - {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"}, - {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"}, - {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"}, - {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"}, - {file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"}, - {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"}, -] - -[package.dependencies] -numpy = [ - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, -] -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.7" - -[package.extras] -all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] -aws = ["s3fs (>=2022.11.0)"] -clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] -compression = ["zstandard (>=0.19.0)"] -computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] -feather = ["pyarrow (>=10.0.1)"] -fss = ["fsspec (>=2022.11.0)"] -gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] -hdf5 = ["tables (>=3.8.0)"] -html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] -mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] -parquet = ["pyarrow (>=10.0.1)"] -performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] -plot = ["matplotlib (>=3.6.3)"] -postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] -pyarrow = ["pyarrow (>=10.0.1)"] -spss = ["pyreadstat (>=1.2.0)"] -sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.9.2)"] - -[[package]] -name = "pandocfilters" -version = "1.5.1" -description = "Utilities for writing pandoc filters in python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, - {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, -] - -[[package]] -name = "parso" -version = "0.8.4" -description = "A Python Parser" -optional = false -python-versions = ">=3.6" -files = [ - {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, - {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, -] - -[package.extras] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["docopt", "pytest"] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pillow" -version = "10.3.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] -fpx = ["olefile"] -mic = ["olefile"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] -typing = ["typing-extensions"] -xmp = ["defusedxml"] - -[[package]] -name = "platformdirs" -version = "4.2.2" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "plum-dispatch" -version = "1.7.4" -description = "Multiple dispatch in Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "plum-dispatch-1.7.4.tar.gz", hash = "sha256:1c1d15b2842b5fa98405fd3dff6fad4887bdc77b60bd200e209d76ebfe9990fe"}, - {file = "plum_dispatch-1.7.4-py3-none-any.whl", hash = "sha256:c40dbeab269bbbf972ce0dbc078380da19ebaee1a370a2c564e1814a11bde216"}, -] - -[[package]] -name = "plum-dispatch" -version = "2.3.6" -description = "Multiple dispatch in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "plum_dispatch-2.3.6-py3-none-any.whl", hash = "sha256:ad0e6f1aa40f6b0bd286e0c24bc5928545095e61dc7b07d19455a7f3b064c907"}, - {file = "plum_dispatch-2.3.6.tar.gz", hash = "sha256:664e79003076aac754127fe9d667f43cf22e448a179d46ddfe298f18c012551d"}, -] - -[package.dependencies] -beartype = ">=0.16.2" -rich = ">=10.0" -typing-extensions = {version = "*", markers = "python_version <= \"3.10\""} - -[package.extras] -dev = ["black (==23.9.0)", "build", "coveralls", "ghp-import", "ipython", "jupyter-book", "mypy", "numpy", "pre-commit", "pyright (>=1.1.331)", "pytest (>=6)", "pytest-cov", "ruff (==0.1.0)", "sybil", "tox", "wheel"] - -[[package]] -name = "prometheus-client" -version = "0.20.0" -description = "Python client for the Prometheus monitoring system." -optional = false -python-versions = ">=3.8" -files = [ - {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, - {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, -] - -[package.extras] -twisted = ["twisted"] - -[[package]] -name = "prompt-toolkit" -version = "3.0.43" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, -] - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "psutil" -version = "5.9.8" -description = "Cross-platform lib for process and system monitoring in Python." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -files = [ - {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, - {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, - {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, - {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, - {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, - {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, - {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, - {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, - {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, - {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, -] - -[package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -optional = false -python-versions = "*" -files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "pycparser" -version = "2.22" -description = "C parser in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, -] - -[[package]] -name = "pydantic" -version = "2.7.1" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.18.2" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pygments" -version = "2.18.0" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pyparsing" -version = "3.1.2" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -optional = false -python-versions = ">=3.6.8" -files = [ - {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, - {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pyproj" -version = "3.6.1" -description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pyproj-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab7aa4d9ff3c3acf60d4b285ccec134167a948df02347585fdd934ebad8811b4"}, - {file = "pyproj-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc0472302919e59114aa140fd7213c2370d848a7249d09704f10f5b062031fe"}, - {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5279586013b8d6582e22b6f9e30c49796966770389a9d5b85e25a4223286cd3f"}, - {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fafd1f3eb421694857f254a9bdbacd1eb22fc6c24ca74b136679f376f97d35"}, - {file = "pyproj-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c41e80ddee130450dcb8829af7118f1ab69eaf8169c4bf0ee8d52b72f098dc2f"}, - {file = "pyproj-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:db3aedd458e7f7f21d8176f0a1d924f1ae06d725228302b872885a1c34f3119e"}, - {file = "pyproj-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebfbdbd0936e178091309f6cd4fcb4decd9eab12aa513cdd9add89efa3ec2882"}, - {file = "pyproj-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:447db19c7efad70ff161e5e46a54ab9cc2399acebb656b6ccf63e4bc4a04b97a"}, - {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e13c40183884ec7f94eb8e0f622f08f1d5716150b8d7a134de48c6110fee85"}, - {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65ad699e0c830e2b8565afe42bd58cc972b47d829b2e0e48ad9638386d994915"}, - {file = "pyproj-3.6.1-cp311-cp311-win32.whl", hash = "sha256:8b8acc31fb8702c54625f4d5a2a6543557bec3c28a0ef638778b7ab1d1772132"}, - {file = "pyproj-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:38a3361941eb72b82bd9a18f60c78b0df8408416f9340521df442cebfc4306e2"}, - {file = "pyproj-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1e9fbaf920f0f9b4ee62aab832be3ae3968f33f24e2e3f7fbb8c6728ef1d9746"}, - {file = "pyproj-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d227a865356f225591b6732430b1d1781e946893789a609bb34f59d09b8b0f8"}, - {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83039e5ae04e5afc974f7d25ee0870a80a6bd6b7957c3aca5613ccbe0d3e72bf"}, - {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb059ba3bced6f6725961ba758649261d85ed6ce670d3e3b0a26e81cf1aa8d"}, - {file = "pyproj-3.6.1-cp312-cp312-win32.whl", hash = "sha256:2d6ff73cc6dbbce3766b6c0bce70ce070193105d8de17aa2470009463682a8eb"}, - {file = "pyproj-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:7a27151ddad8e1439ba70c9b4b2b617b290c39395fa9ddb7411ebb0eb86d6fb0"}, - {file = "pyproj-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ba1f9b03d04d8cab24d6375609070580a26ce76eaed54631f03bab00a9c737b"}, - {file = "pyproj-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18faa54a3ca475bfe6255156f2f2874e9a1c8917b0004eee9f664b86ccc513d3"}, - {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd43bd9a9b9239805f406fd82ba6b106bf4838d9ef37c167d3ed70383943ade1"}, - {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50100b2726a3ca946906cbaa789dd0749f213abf0cbb877e6de72ca7aa50e1ae"}, - {file = "pyproj-3.6.1-cp39-cp39-win32.whl", hash = "sha256:9274880263256f6292ff644ca92c46d96aa7e57a75c6df3f11d636ce845a1877"}, - {file = "pyproj-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:36b64c2cb6ea1cc091f329c5bd34f9c01bb5da8c8e4492c709bda6a09f96808f"}, - {file = "pyproj-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd93c1a0c6c4aedc77c0fe275a9f2aba4d59b8acf88cebfc19fe3c430cfabf4f"}, - {file = "pyproj-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6420ea8e7d2a88cb148b124429fba8cd2e0fae700a2d96eab7083c0928a85110"}, - {file = "pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf"}, -] - -[package.dependencies] -certifi = "*" - -[[package]] -name = "pytest" -version = "8.2.1" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.5,<2.0" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "5.0.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, -] - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-json-logger" -version = "2.0.7" -description = "A python library adding a json log formatter" -optional = false -python-versions = ">=3.6" -files = [ - {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, - {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, -] - -[[package]] -name = "pytz" -version = "2024.1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, -] - -[[package]] -name = "pywin32" -version = "306" -description = "Python for Window Extensions" -optional = false -python-versions = "*" -files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, -] - -[[package]] -name = "pywinpty" -version = "2.0.13" -description = "Pseudo terminal support for Windows from Python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pywinpty-2.0.13-cp310-none-win_amd64.whl", hash = "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56"}, - {file = "pywinpty-2.0.13-cp311-none-win_amd64.whl", hash = "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99"}, - {file = "pywinpty-2.0.13-cp312-none-win_amd64.whl", hash = "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4"}, - {file = "pywinpty-2.0.13-cp38-none-win_amd64.whl", hash = "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d"}, - {file = "pywinpty-2.0.13-cp39-none-win_amd64.whl", hash = "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b"}, - {file = "pywinpty-2.0.13.tar.gz", hash = "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" -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"}, -] - -[[package]] -name = "pyzmq" -version = "26.0.3" -description = "Python bindings for 0MQ" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, - {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, - {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, - {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, - {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, - {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, - {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, - {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, -] - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "qtconsole" -version = "5.5.2" -description = "Jupyter Qt console" -optional = false -python-versions = ">=3.8" -files = [ - {file = "qtconsole-5.5.2-py3-none-any.whl", hash = "sha256:42d745f3d05d36240244a04e1e1ec2a86d5d9b6edb16dbdef582ccb629e87e0b"}, - {file = "qtconsole-5.5.2.tar.gz", hash = "sha256:6b5fb11274b297463706af84dcbbd5c92273b1f619e6d25d08874b0a88516989"}, -] - -[package.dependencies] -ipykernel = ">=4.1" -jupyter-client = ">=4.1" -jupyter-core = "*" -packaging = "*" -pygments = "*" -pyzmq = ">=17.1" -qtpy = ">=2.4.0" -traitlets = "<5.2.1 || >5.2.1,<5.2.2 || >5.2.2" - -[package.extras] -doc = ["Sphinx (>=1.3)"] -test = ["flaky", "pytest", "pytest-qt"] - -[[package]] -name = "qtpy" -version = "2.4.1" -description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." -optional = false -python-versions = ">=3.7" -files = [ - {file = "QtPy-2.4.1-py3-none-any.whl", hash = "sha256:1c1d8c4fa2c884ae742b069151b0abe15b3f70491f3972698c683b8e38de839b"}, - {file = "QtPy-2.4.1.tar.gz", hash = "sha256:a5a15ffd519550a1361bdc56ffc07fda56a6af7292f17c7b395d4083af632987"}, -] - -[package.dependencies] -packaging = "*" - -[package.extras] -test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] - -[[package]] -name = "quartodoc" -version = "0.7.2" -description = "Generate API documentation with Quarto." -optional = false -python-versions = ">=3.9" -files = [ - {file = "quartodoc-0.7.2-py3-none-any.whl", hash = "sha256:adff974296c013308f4e06cadea8b71b90d334dcb1510d2bd0ef9cea06d8be98"}, - {file = "quartodoc-0.7.2.tar.gz", hash = "sha256:58f98c88065ce0b4a857f13282d1e38bb2cd4757b481a4c6279bdca89ba5640b"}, -] - -[package.dependencies] -click = "*" -griffe = ">=0.33" -importlib-metadata = ">=5.1.0" -importlib-resources = ">=5.10.2" -plum-dispatch = [ - {version = "<2.0.0", markers = "python_version < \"3.10\""}, - {version = ">2.0.0", markers = "python_version >= \"3.10\""}, -] -pydantic = "*" -pyyaml = "*" -sphobjinv = ">=2.3.1" -tabulate = ">=0.9.0" -typing-extensions = ">=4.4.0" -watchdog = ">=3.0.0" - -[package.extras] -dev = ["jupyterlab", "jupytext", "pre-commit", "pytest", "syrupy"] - -[[package]] -name = "rasterio" -version = "1.3.10" -description = "Fast and direct raster I/O for use with Numpy and SciPy" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rasterio-1.3.10-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2ef27c3eff6f44f8b5d5de228003367c1843593edf648d85c0dc1319c00dc57d"}, - {file = "rasterio-1.3.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c711b497e9ef0c4f5e1c01e34ba910708e066e1c4a69c25df18d1bcc04481287"}, - {file = "rasterio-1.3.10-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:d1ac85857144cb8075e332e9d908b65426d30ddc1f59f7a04bcf6ed6fd3c0d47"}, - {file = "rasterio-1.3.10-cp310-cp310-win_amd64.whl", hash = "sha256:ef8a496740df1e68f7a3d3449aa3be9c3210c22f4bb78a4a9e1c290183abd9b1"}, - {file = "rasterio-1.3.10-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:97d867cada29f16cb83f1743217f775f8b982676fcdda77671d25abb26698159"}, - {file = "rasterio-1.3.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:505b3e659eb3b137192c25233bf7954bc4997b1a474bae9e129fbd5ac2619404"}, - {file = "rasterio-1.3.10-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:30f27e309a14a70c821d10a0ea18b110968dc2e2186b06a900aebd92094f4e00"}, - {file = "rasterio-1.3.10-cp311-cp311-win_amd64.whl", hash = "sha256:cbb2eea127328302f9e3158a000363a7d9eea22537378dee4f824a7fa2d78c05"}, - {file = "rasterio-1.3.10-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:3a9c4fb63e050e11bcd23e53f084ca186b445f976df1f70e7abd851c4072837f"}, - {file = "rasterio-1.3.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c7ddca79444fd3b933f4cd1a1773e9f7839d0ce5d76e600bdf92ee9a79b95f8"}, - {file = "rasterio-1.3.10-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f9cd757e11cfb07ef39b1cc79a32497bf22aff7fec41fe330b868cb3043b4db5"}, - {file = "rasterio-1.3.10-cp312-cp312-win_amd64.whl", hash = "sha256:7e653968f64840654d277e0f86f8666ed8f3030ba36fa865f420f9bc38d619ee"}, - {file = "rasterio-1.3.10-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:7a22c0e0cf07dbed6576faf9a49bc4afa1afedd5a14441b64a3d3dd6d10dc274"}, - {file = "rasterio-1.3.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d29d30c2271fa265913bd3db93fa213d3a0894362ec704e7273cf30443098a90"}, - {file = "rasterio-1.3.10-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:287e8d0d0472c778aa0b6392e9c00894a80f2bace28fa6eddb76c0a895097947"}, - {file = "rasterio-1.3.10-cp38-cp38-win_amd64.whl", hash = "sha256:a420e5f25108b1c92c5d071cfd6518b3766f20a6eddb1b322d06c3d46a89fab6"}, - {file = "rasterio-1.3.10-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:73ea4d0e584f696ef115601bbb97ba8d2b68a67c2bb3b40999414d31b6c7cf89"}, - {file = "rasterio-1.3.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e6eece6420d7d6ef9b9830633b8fcd15e86b8702cb13419abe251c16ca502cf3"}, - {file = "rasterio-1.3.10-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:0bbd62b45a35cab53cb7fe72419e823e47ab31ee2d055af8e21dc7f37fe5ed6c"}, - {file = "rasterio-1.3.10-cp39-cp39-win_amd64.whl", hash = "sha256:450f2bd45335308829da90566fbcbdb8e8aa0251a9d1f6ebb60667855dfb7554"}, - {file = "rasterio-1.3.10.tar.gz", hash = "sha256:ce182c735b4f9e8735d90600607ecab15ef895eb8aa660bf665751529477e326"}, -] - -[package.dependencies] -affine = "*" -attrs = "*" -certifi = "*" -click = ">=4.0" -click-plugins = "*" -cligj = ">=0.5" -importlib-metadata = {version = "*", markers = "python_version < \"3.10\""} -numpy = "*" -setuptools = "*" -snuggs = ">=1.4.1" - -[package.extras] -all = ["boto3 (>=1.2.4)", "ghp-import", "hypothesis", "ipython (>=2.0)", "matplotlib", "numpydoc", "packaging", "pytest (>=2.8.2)", "pytest-cov (>=2.2.0)", "shapely", "sphinx", "sphinx-rtd-theme"] -docs = ["ghp-import", "numpydoc", "sphinx", "sphinx-rtd-theme"] -ipython = ["ipython (>=2.0)"] -plot = ["matplotlib"] -s3 = ["boto3 (>=1.2.4)"] -test = ["boto3 (>=1.2.4)", "hypothesis", "packaging", "pytest (>=2.8.2)", "pytest-cov (>=2.2.0)", "shapely"] - -[[package]] -name = "referencing" -version = "0.35.1" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" - -[[package]] -name = "requests" -version = "2.32.0" -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"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -description = "A pure python RFC3339 validator" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, - {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, -] - -[package.dependencies] -six = "*" - -[[package]] -name = "rfc3986-validator" -version = "0.1.1" -description = "Pure python rfc3986 validator" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, - {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, -] - -[[package]] -name = "rich" -version = "13.7.1" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "rpds-py" -version = "0.18.1" -description = "Python bindings to Rust's persistent data structures (rpds)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, - {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, - {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, - {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, - {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, - {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, - {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, - {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, - {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, - {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, - {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, - {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, - {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, -] - -[[package]] -name = "scikit-learn" -version = "1.5.0" -description = "A set of python modules for machine learning and data mining" -optional = false -python-versions = ">=3.9" -files = [ - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12e40ac48555e6b551f0a0a5743cc94cc5a765c9513fe708e01f0aa001da2801"}, - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f405c4dae288f5f6553b10c4ac9ea7754d5180ec11e296464adb5d6ac68b6ef5"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df8ccabbf583315f13160a4bb06037bde99ea7d8211a69787a6b7c5d4ebb6fc3"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c75ea812cd83b1385bbfa94ae971f0d80adb338a9523f6bbcb5e0b0381151d4"}, - {file = "scikit_learn-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:a90c5da84829a0b9b4bf00daf62754b2be741e66b5946911f5bdfaa869fcedd6"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a65af2d8a6cce4e163a7951a4cfbfa7fceb2d5c013a4b593686c7f16445cf9d"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:4c0c56c3005f2ec1db3787aeaabefa96256580678cec783986836fc64f8ff622"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f77547165c00625551e5c250cefa3f03f2fc92c5e18668abd90bfc4be2e0bff"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:118a8d229a41158c9f90093e46b3737120a165181a1b58c03461447aa4657415"}, - {file = "scikit_learn-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:a03b09f9f7f09ffe8c5efffe2e9de1196c696d811be6798ad5eddf323c6f4d40"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:460806030c666addee1f074788b3978329a5bfdc9b7d63e7aad3f6d45c67a210"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1b94d6440603752b27842eda97f6395f570941857456c606eb1d638efdb38184"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d82c2e573f0f2f2f0be897e7a31fcf4e73869247738ab8c3ce7245549af58ab8"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3a10e1d9e834e84d05e468ec501a356226338778769317ee0b84043c0d8fb06"}, - {file = "scikit_learn-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:855fc5fa8ed9e4f08291203af3d3e5fbdc4737bd617a371559aaa2088166046e"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:40fb7d4a9a2db07e6e0cae4dc7bdbb8fada17043bac24104d8165e10e4cff1a2"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:47132440050b1c5beb95f8ba0b2402bbd9057ce96ec0ba86f2f445dd4f34df67"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174beb56e3e881c90424e21f576fa69c4ffcf5174632a79ab4461c4c960315ac"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261fe334ca48f09ed64b8fae13f9b46cc43ac5f580c4a605cbb0a517456c8f71"}, - {file = "scikit_learn-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:057b991ac64b3e75c9c04b5f9395eaf19a6179244c089afdebaad98264bff37c"}, - {file = "scikit_learn-1.5.0.tar.gz", hash = "sha256:789e3db01c750ed6d496fa2db7d50637857b451e57bcae863bff707c1247bef7"}, -] - -[package.dependencies] -joblib = ">=1.2.0" -numpy = ">=1.19.5" -scipy = ">=1.6.0" -threadpoolctl = ">=3.1.0" - -[package.extras] -benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.15.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] -install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] -maintenance = ["conda-lock (==2.5.6)"] -tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] - -[[package]] -name = "scipy" -version = "1.13.0" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = ">=3.9" -files = [ - {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"}, - {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"}, - {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"}, - {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"}, - {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"}, - {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"}, - {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"}, - {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"}, - {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"}, - {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"}, - {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"}, -] - -[package.dependencies] -numpy = ">=1.22.4,<2.3" - -[package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] -test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - -[[package]] -name = "send2trash" -version = "1.8.3" -description = "Send file to trash natively under Mac OS X, Windows and Linux" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"}, - {file = "Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf"}, -] - -[package.extras] -nativelib = ["pyobjc-framework-Cocoa", "pywin32"] -objc = ["pyobjc-framework-Cocoa"] -win32 = ["pywin32"] - -[[package]] -name = "setuptools" -version = "70.0.0" -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"}, -] - -[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"] - -[[package]] -name = "shapely" -version = "2.0.4" -description = "Manipulation and analysis of geometric objects" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:011b77153906030b795791f2fdfa2d68f1a8d7e40bce78b029782ade3afe4f2f"}, - {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9831816a5d34d5170aa9ed32a64982c3d6f4332e7ecfe62dc97767e163cb0b17"}, - {file = "shapely-2.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c4849916f71dc44e19ed370421518c0d86cf73b26e8656192fcfcda08218fbd"}, - {file = "shapely-2.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:841f93a0e31e4c64d62ea570d81c35de0f6cea224568b2430d832967536308e6"}, - {file = "shapely-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b4431f522b277c79c34b65da128029a9955e4481462cbf7ebec23aab61fc58"}, - {file = "shapely-2.0.4-cp310-cp310-win32.whl", hash = "sha256:92a41d936f7d6743f343be265ace93b7c57f5b231e21b9605716f5a47c2879e7"}, - {file = "shapely-2.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:30982f79f21bb0ff7d7d4a4e531e3fcaa39b778584c2ce81a147f95be1cd58c9"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0205cb21ad5ddaef607cda9a3191eadd1e7a62a756ea3a356369675230ac35"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d56ce3e2a6a556b59a288771cf9d091470116867e578bebced8bfc4147fbfd7"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58b0ecc505bbe49a99551eea3f2e8a9b3b24b3edd2a4de1ac0dc17bc75c9ec07"}, - {file = "shapely-2.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:790a168a808bd00ee42786b8ba883307c0e3684ebb292e0e20009588c426da47"}, - {file = "shapely-2.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4310b5494271e18580d61022c0857eb85d30510d88606fa3b8314790df7f367d"}, - {file = "shapely-2.0.4-cp311-cp311-win32.whl", hash = "sha256:63f3a80daf4f867bd80f5c97fbe03314348ac1b3b70fb1c0ad255a69e3749879"}, - {file = "shapely-2.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:c52ed79f683f721b69a10fb9e3d940a468203f5054927215586c5d49a072de8d"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5bbd974193e2cc274312da16b189b38f5f128410f3377721cadb76b1e8ca5328"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:41388321a73ba1a84edd90d86ecc8bfed55e6a1e51882eafb019f45895ec0f65"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0776c92d584f72f1e584d2e43cfc5542c2f3dd19d53f70df0900fda643f4bae6"}, - {file = "shapely-2.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c75c98380b1ede1cae9a252c6dc247e6279403fae38c77060a5e6186c95073ac"}, - {file = "shapely-2.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e700abf4a37b7b8b90532fa6ed5c38a9bfc777098bc9fbae5ec8e618ac8f30"}, - {file = "shapely-2.0.4-cp312-cp312-win32.whl", hash = "sha256:4f2ab0faf8188b9f99e6a273b24b97662194160cc8ca17cf9d1fb6f18d7fb93f"}, - {file = "shapely-2.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:03152442d311a5e85ac73b39680dd64a9892fa42bb08fd83b3bab4fe6999bfa0"}, - {file = "shapely-2.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:994c244e004bc3cfbea96257b883c90a86e8cbd76e069718eb4c6b222a56f78b"}, - {file = "shapely-2.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ffd6491e9e8958b742b0e2e7c346635033d0a5f1a0ea083547fcc854e5d5cf"}, - {file = "shapely-2.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbdc1140a7d08faa748256438291394967aa54b40009f54e8d9825e75ef6113"}, - {file = "shapely-2.0.4-cp37-cp37m-win32.whl", hash = "sha256:5af4cd0d8cf2912bd95f33586600cac9c4b7c5053a036422b97cfe4728d2eb53"}, - {file = "shapely-2.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:464157509ce4efa5ff285c646a38b49f8c5ef8d4b340f722685b09bb033c5ccf"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:489c19152ec1f0e5c5e525356bcbf7e532f311bff630c9b6bc2db6f04da6a8b9"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b79bbd648664aa6f44ef018474ff958b6b296fed5c2d42db60078de3cffbc8aa"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:674d7baf0015a6037d5758496d550fc1946f34bfc89c1bf247cabdc415d7747e"}, - {file = "shapely-2.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cd4ccecc5ea5abd06deeaab52fcdba372f649728050c6143cc405ee0c166679"}, - {file = "shapely-2.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb5cdcbbe3080181498931b52a91a21a781a35dcb859da741c0345c6402bf00c"}, - {file = "shapely-2.0.4-cp38-cp38-win32.whl", hash = "sha256:55a38dcd1cee2f298d8c2ebc60fc7d39f3b4535684a1e9e2f39a80ae88b0cea7"}, - {file = "shapely-2.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec555c9d0db12d7fd777ba3f8b75044c73e576c720a851667432fabb7057da6c"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9103abd1678cb1b5f7e8e1af565a652e036844166c91ec031eeb25c5ca8af0"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:263bcf0c24d7a57c80991e64ab57cba7a3906e31d2e21b455f493d4aab534aaa"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddf4a9bfaac643e62702ed662afc36f6abed2a88a21270e891038f9a19bc08fc"}, - {file = "shapely-2.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:485246fcdb93336105c29a5cfbff8a226949db37b7473c89caa26c9bae52a242"}, - {file = "shapely-2.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8de4578e838a9409b5b134a18ee820730e507b2d21700c14b71a2b0757396acc"}, - {file = "shapely-2.0.4-cp39-cp39-win32.whl", hash = "sha256:9dab4c98acfb5fb85f5a20548b5c0abe9b163ad3525ee28822ffecb5c40e724c"}, - {file = "shapely-2.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:31c19a668b5a1eadab82ff070b5a260478ac6ddad3a5b62295095174a8d26398"}, - {file = "shapely-2.0.4.tar.gz", hash = "sha256:5dc736127fac70009b8d309a0eeb74f3e08979e530cf7017f2f507ef62e6cfb8"}, -] - -[package.dependencies] -numpy = ">=1.14,<3" - -[package.extras] -docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] -test = ["pytest", "pytest-cov"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "snuggs" -version = "1.4.7" -description = "Snuggs are s-expressions for Numpy" -optional = false -python-versions = "*" -files = [ - {file = "snuggs-1.4.7-py3-none-any.whl", hash = "sha256:988dde5d4db88e9d71c99457404773dabcc7a1c45971bfbe81900999942d9f07"}, - {file = "snuggs-1.4.7.tar.gz", hash = "sha256:501cf113fe3892e14e2fee76da5cd0606b7e149c411c271898e6259ebde2617b"}, -] - -[package.dependencies] -numpy = "*" -pyparsing = ">=2.1.6" - -[package.extras] -test = ["hypothesis", "pytest"] - -[[package]] -name = "soupsieve" -version = "2.5" -description = "A modern CSS selector implementation for Beautiful Soup." -optional = false -python-versions = ">=3.8" -files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, -] - -[[package]] -name = "sphobjinv" -version = "2.3.1" -description = "Sphinx objects.inv Inspection/Manipulation Tool" -optional = false -python-versions = ">=3.6" -files = [ - {file = "sphobjinv-2.3.1-py3-none-any.whl", hash = "sha256:f3efe68bb0ba6e32cb50df064fe6349b8f94681589b400dea753a2860dd576b5"}, - {file = "sphobjinv-2.3.1.tar.gz", hash = "sha256:1442a47fc93587a0177be95346904e388ef85a8366f90a1835a7c3eeeb122eb7"}, -] - -[package.dependencies] -attrs = ">=19.2" -certifi = "*" -jsonschema = ">=3.0" - -[[package]] -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "tabulate" -version = "0.9.0" -description = "Pretty-print tabular data" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, - {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, -] - -[package.extras] -widechars = ["wcwidth"] - -[[package]] -name = "terminado" -version = "0.18.1" -description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." -optional = false -python-versions = ">=3.8" -files = [ - {file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"}, - {file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"}, -] - -[package.dependencies] -ptyprocess = {version = "*", markers = "os_name != \"nt\""} -pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} -tornado = ">=6.1.0" - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] -typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] - -[[package]] -name = "threadpoolctl" -version = "3.5.0" -description = "threadpoolctl" -optional = false -python-versions = ">=3.8" -files = [ - {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, - {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, -] - -[[package]] -name = "tinycss2" -version = "1.3.0" -description = "A tiny CSS parser" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, - {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, -] - -[package.dependencies] -webencodings = ">=0.4" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["pytest", "ruff"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "tornado" -version = "6.4.1" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -optional = false -python-versions = ">=3.8" -files = [ - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, - {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, - {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, - {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, -] - -[[package]] -name = "tqdm" -version = "4.66.4" -description = "Fast, Extensible Progress Meter" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, - {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - -[[package]] -name = "traitlets" -version = "5.14.3" -description = "Traitlets Python configuration system" -optional = false -python-versions = ">=3.8" -files = [ - {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, - {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, -] - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] - -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20240316" -description = "Typing stubs for python-dateutil" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, - {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, -] - -[[package]] -name = "typing-extensions" -version = "4.11.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, -] - -[[package]] -name = "tzdata" -version = "2024.1" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, -] - -[[package]] -name = "uri-template" -version = "1.3.0" -description = "RFC 6570 URI Template Processor" -optional = false -python-versions = ">=3.7" -files = [ - {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, - {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, -] - -[package.extras] -dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] - -[[package]] -name = "urllib3" -version = "2.2.2" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "watchdog" -version = "4.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.8" -files = [ - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, - {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, - {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, - {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, - {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, - {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, - {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, - {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, -] - -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - -[[package]] -name = "wcwidth" -version = "0.2.13" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, -] - -[[package]] -name = "webcolors" -version = "1.13" -description = "A library for working with the color formats defined by HTML and CSS." -optional = false -python-versions = ">=3.7" -files = [ - {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, - {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, -] - -[package.extras] -docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] -tests = ["pytest", "pytest-cov"] - -[[package]] -name = "webencodings" -version = "0.5.1" -description = "Character encoding aliases for legacy web content" -optional = false -python-versions = "*" -files = [ - {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, - {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, -] - -[[package]] -name = "websocket-client" -version = "1.8.0" -description = "WebSocket client for Python with low level API options" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, - {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, -] - -[package.extras] -docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"] -optional = ["python-socks", "wsaccel"] -test = ["websockets"] - -[[package]] -name = "widgetsnbextension" -version = "4.0.10" -description = "Jupyter interactive widgets for Jupyter Notebook" -optional = false -python-versions = ">=3.7" -files = [ - {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, - {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, -] - -[[package]] -name = "zipp" -version = "3.19.1" -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"}, -] - -[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)"] - -[metadata] -lock-version = "2.0" -python-versions = "^3.9" -content-hash = "bf7c6f5381b05736028478841d632497697d24e516a232bb7cc6570223c68449" diff --git a/pyproject.toml b/pyproject.toml index 78bea26..311b278 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,37 +1,47 @@ -[tool.poetry] -name = "pyspatialml" -version = "0.22.1" -description = "Machine learning classification and regression modelling for spatial raster data." -authors = ["Steven Pawley "] -license = "GPL-3.0-or-later" -readme = "README.md" -homepage = "https://stevenpawley.github.io/Pyspatialml/" -repository = "https://github.com/stevenpawley/Pyspatialml" - -[tool.poetry.dependencies] -python = "^3.9" -tqdm = "^4.66.4" -rasterio = "^1.3.10" -geopandas = "^0.14.4" -numpy = "^1.26.4" -scipy = "^1.13.0" -shapely = "^2.0.4" -pandas = "^2.2.2" -matplotlib = "^3.9.0" -scikit-learn = "^1.4.2" -affine = "^2.4.0" - -[tool.poetry.group.dev.dependencies] -quartodoc = "^0.7.2" -jupyter = "^1.0.0" -ipykernel = "^6.29.4" -black = "^24.4.2" - -[tool.poetry.group.test.dependencies] -pytest = "^8.2.0" -pytest-cov = "^5.0.0" -coverage = "^7.5.3" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +# pyproject.toml +[tool.setuptools] +packages = ["pyspatialml"] + +[project] +name = "pyspatialml" +version = "0.22.1" +description = "Machine learning classification and regression modelling for spatial raster data." +authors = [ + {name = "Steven Pawley", email = "dr.stevenpawley@gmail.com"} +] +license = {file = "LICENSE"} +readme = "README.md" +requires-python = ">= 3.9" +dependencies = [ + "tqdm>=4.66.4", + "rasterio>=1.3.10", + "geopandas>=0.14.4", + "numpy>=1.26.4", + "scipy>=1.13.0", + "shapely>=2.0.4", + "pandas>=2.2.2", + "matplotlib>=3.9.0", + "scikit-learn>=1.4.2", + "affine>=2.4.0" +] + +[project.optional-dependencies] +documentation = [ + "quartodoc>=0.7.2", + "jupyter>=1.0.0", + "ipykernel>=6.29.4", + "black>=24.4.2" +] +testing = [ + "pytest>=8.2.0", + "pytest-cov>=5.0.0", + "coverage>=7.5.3" +] + +[project.urls] +homepage = "https://stevenpawley.github.io/Pyspatialml/" +repository = "https://github.com/stevenpawley/Pyspatialml" diff --git a/pyspatialml/__init__.py b/pyspatialml/__init__.py index c5ff929..2b9d722 100644 --- a/pyspatialml/__init__.py +++ b/pyspatialml/__init__.py @@ -1,2 +1,2 @@ -from .raster import Raster -from .rasterlayer import RasterLayer +from .raster import Raster +from .rasterlayer import RasterLayer diff --git a/pyspatialml/_plotting.py b/pyspatialml/_plotting.py index c6357de..f68cd94 100644 --- a/pyspatialml/_plotting.py +++ b/pyspatialml/_plotting.py @@ -1,388 +1,388 @@ -import math - -import rasterio -import matplotlib as mpl -import matplotlib.pyplot as plt -import numpy as np -from mpl_toolkits.axes_grid1 import make_axes_locatable -import matplotlib.ticker as mticker - - -def discrete_cmap(N, base_cmap=None): - """Create an N-bin discrete colormap from the specified input map. - - Source: - https://gist.github.com/jakevdp/91077b0cae40f8f8244a - - Parameters - ---------- - N : int - The number of colors in the colormap - - base_cmap : str - The name of the matplotlib cmap to convert into a discrete map. - - Returns - ------- - matplotlib.cmap - The cmap converted to a discrete map. - """ - - base = plt.cm.get_cmap(base_cmap) - color_list = base(np.linspace(0, 1, N)) - cmap_name = base.name + str(N) - - return base.from_list(cmap_name, color_list, N) - - -class RasterPlotMixin: - def plot( - self, - cmap=None, - norm=None, - figsize=None, - out_shape=(500, 500), - title_fontsize=8, - label_fontsize=6, - legend_fontsize=6, - names=None, - fig_kwds=None, - legend_kwds=None, - subplots_kwds=None, - ): - """Plot a Raster object as a raster matrix - - Parameters - ---------- - cmap : str (opt), default=None - Specify a single cmap to apply to all of the RasterLayers. - This overides the cmap attribute of each RasterLayer. - - norm : matplotlib.colors.Normalize (opt), default=None - A matplotlib.colors.Normalize to apply to all of the - RasterLayers. This overides the norm attribute of each - RasterLayer. - - figsize : tuple (opt), default=None - Size of the resulting matplotlib.figure.Figure. - - out_shape : tuple, default=(500, 500) - Number of rows, cols to read from the raster datasets for - plotting. - - title_fontsize : any number, default=8 - Size in pts of titles. - - label_fontsize : any number, default=6 - Size in pts of axis ticklabels. - - legend_fontsize : any number, default=6 - Size in pts of legend ticklabels. - - names : list (opt), default=None - Optionally supply a list of names for each RasterLayer to - override the default layer names for the titles. - - fig_kwds : dict (opt), default=None - Additional arguments to pass to the - matplotlib.pyplot.figure call when creating the figure - object. - - legend_kwds : dict (opt), default=None - Additional arguments to pass to the - matplotlib.pyplot.colorbar call when creating the colorbar - object. - - subplots_kwds : dict (opt), default=None - Additional arguments to pass to the - matplotlib.pyplot.subplots_adjust function. These are used to - control the spacing and position of each subplot, and can - include{left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None}. - - Returns - ------- - axs : numpy.ndarray - array of matplotlib.axes._subplots.AxesSubplot or a single - matplotlib.axes._subplots.AxesSubplot if Raster object - contains only a single layer. - """ - - # some checks - if norm: - if not isinstance(norm, mpl.colors.Normalize): - raise AttributeError( - "norm argument should be a matplotlib.colors.Normalize object" - ) - - if cmap: - cmaps = [cmap for i in self.iloc] - else: - cmaps = [i.cmap for i in self.iloc] - - if norm: - norms = [norm for i in self.iloc] - else: - norms = [i.norm for i in self.iloc] - - if names is None: - names = self.names - else: - if len(names) != self.count: - raise AttributeError( - "arguments 'names' needs to be the same length as the number of " - "RasterLayer objects " - ) - - if fig_kwds is None: - fig_kwds = {} - - if legend_kwds is None: - legend_kwds = {} - - if subplots_kwds is None: - subplots_kwds = {} - - if figsize: - fig_kwds["figsize"] = figsize - - # estimate required number of rows and columns in figure - rows = int(np.sqrt(self.count)) - cols = int(math.ceil(np.sqrt(self.count))) - - if rows * cols < self.count: - rows += 1 - - fig, axs = plt.subplots(rows, cols, **fig_kwds) - - # axs.flat is an iterator over the row-order flattened axs array - if isinstance(axs, np.ndarray): - for ax, n, cmap, norm, name in zip( - axs.flat, range(self.count), cmaps, norms, names - ): - - arr = self.iloc[n].read(masked=True, out_shape=out_shape) - ax.set_title(name, fontsize=title_fontsize, y=1.00) - - im = ax.imshow( - arr, - extent=[ - self.bounds.left, - self.bounds.right, - self.bounds.bottom, - self.bounds.top, - ], - cmap=cmap, - norm=norm, - ) - - divider = make_axes_locatable(ax) - - if "orientation" not in legend_kwds.keys(): - legend_kwds["orientation"] = "vertical" - - if legend_kwds["orientation"] == "vertical": - legend_pos = "right" - - elif legend_kwds["orientation"] == "horizontal": - legend_pos = "bottom" - - cax = divider.append_axes(legend_pos, size="10%", pad=0.1) - cbar = plt.colorbar(im, cax=cax, **legend_kwds) - cbar.ax.tick_params(labelsize=legend_fontsize) - - # hide tick labels by default when multiple rows or cols - ax.axes.get_xaxis().set_ticklabels([]) - ax.axes.get_yaxis().set_ticklabels([]) - - # show y-axis tick labels on first subplot - if n == 0 and rows > 1: - ticks_loc = ax.get_yticks().tolist() - ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) - ax.set_yticklabels( - ax.yaxis.get_majorticklocs().astype("int"), - fontsize=label_fontsize, - ) - - if n == 0 and rows == 1: - ticks_loc = ax.get_xticks().tolist() - ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) - ax.set_xticklabels( - ax.xaxis.get_majorticklocs().astype("int"), - fontsize=label_fontsize, - ) - - ticks_loc = ax.get_yticks().tolist() - ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) - ax.set_yticklabels( - ax.yaxis.get_majorticklocs().astype("int"), - fontsize=label_fontsize, - ) - - if rows > 1 and n == (rows * cols) - cols: - ticks_loc = ax.get_xticks().tolist() - ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) - ax.set_xticklabels( - ax.xaxis.get_majorticklocs().astype("int"), - fontsize=label_fontsize, - ) - - for ax in axs.flat[axs.size - 1 : self.count - 1 : -1]: - ax.set_visible(False) - - plt.subplots_adjust(**subplots_kwds) - - else: - arr = self.iloc[0].read(masked=True, out_shape=out_shape) - cmap = cmaps[0] - norm = norms[0] - axs.set_title(list(names)[0], fontsize=title_fontsize, y=1.00) - im = axs.imshow( - arr, - extent=[ - self.bounds.left, - self.bounds.right, - self.bounds.bottom, - self.bounds.top, - ], - cmap=cmap, - norm=norm, - ) - - divider = make_axes_locatable(axs) - - if "orientation" not in legend_kwds.keys(): - legend_kwds["orientation"] = "vertical" - - if legend_kwds["orientation"] == "vertical": - legend_pos = "right" - - elif legend_kwds["orientation"] == "horizontal": - legend_pos = "bottom" - - cax = divider.append_axes(legend_pos, size="10%", pad=0.1) - cbar = plt.colorbar(im, cax=cax, **legend_kwds) - cbar.ax.tick_params(labelsize=legend_fontsize) - - return axs - - -class RasterLayerPlotMixin: - def plot( - self, - cmap=None, - norm=None, - ax=None, - cax=None, - figsize=None, - out_shape=(500, 500), - categorical=None, - legend=False, - vmin=None, - vmax=None, - fig_kwds=None, - legend_kwds=None, - ): - """Plot a RasterLayer using matplotlib.pyplot.imshow - - Parameters - ---------- - cmap : str (default None) - The name of a colormap recognized by matplotlib. - Overrides the cmap attribute of the RasterLayer. - - norm : matplotlib.colors.Normalize (opt) - A matplotlib.colors.Normalize to apply to the RasterLayer. - This overrides the norm attribute of the RasterLayer. - - ax : matplotlib.pyplot.Artist (optional, default None) - axes instance on which to draw to plot. - - cax : matplotlib.pyplot.Artist (optional, default None) - axes on which to draw the legend. - - figsize : tuple of integers (optional, default None) - Size of the matplotlib.figure.Figure. If the ax argument is - given explicitly, figsize is ignored. - - out_shape : tuple, default=(500, 500) - Number of rows, cols to read from the raster datasets for - plotting. - - categorical : bool (optional, default False) - if True then the raster values will be considered to - represent discrete values, otherwise they are considered to - represent continuous values. This overrides the - RasterLayer 'categorical' attribute. Setting the argument - categorical to True is ignored if the - RasterLayer.categorical is already True. - - legend : bool (optional, default False) - Whether to plot the legend. - - vmin, xmax : scale (optional, default None) - vmin and vmax define the data range that the colormap - covers. By default, the colormap covers the complete value - range of the supplied data. vmin, vmax are ignored if the - norm parameter is used. - - fig_kwds : dict (optional, default None) - Additional arguments to pass to the - matplotlib.pyplot.figure call when creating the figure - object. Ignored if ax is passed to the plot function. - - legend_kwds : dict (optional, default None) - Keyword arguments to pass to matplotlib.pyplot.colorbar(). - - Returns - ------- - ax : matplotlib axes instance - """ - - # some checks - if fig_kwds is None: - fig_kwds = {} - - if ax is None: - if cax is not None: - raise ValueError("'ax' can not be None if 'cax' is not.") - fig, ax = plt.subplots(figsize=figsize, **fig_kwds) - - ax.set_aspect("equal") - - if norm: - if not isinstance(norm, mpl.colors.Normalize): - raise AttributeError( - "norm argument should be a " "matplotlib.colors.Normalize object" - ) - - if cmap is None: - cmap = self.cmap - - if norm is None: - norm = self.norm - - if legend_kwds is None: - legend_kwds = {} - - arr = self.read(masked=True, out_shape=out_shape) - - if categorical is True: - if self.categorical is False: - N = np.bincount(arr) - cmap = discrete_cmap(N, base_cmap=cmap) - vmin, vmax = None, None - - im = ax.imshow( - X=arr, - extent=rasterio.plot.plotting_extent(self.ds), - cmap=cmap, - norm=norm, - vmin=vmin, - vmax=vmax, - ) - - if legend is True: - plt.colorbar(im, cax=cax, ax=ax, **legend_kwds) - - return ax +import math + +import rasterio +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np +from mpl_toolkits.axes_grid1 import make_axes_locatable +import matplotlib.ticker as mticker + + +def discrete_cmap(N, base_cmap=None): + """Create an N-bin discrete colormap from the specified input map. + + Source: + https://gist.github.com/jakevdp/91077b0cae40f8f8244a + + Parameters + ---------- + N : int + The number of colors in the colormap + + base_cmap : str + The name of the matplotlib cmap to convert into a discrete map. + + Returns + ------- + matplotlib.cmap + The cmap converted to a discrete map. + """ + + base = plt.cm.get_cmap(base_cmap) + color_list = base(np.linspace(0, 1, N)) + cmap_name = base.name + str(N) + + return base.from_list(cmap_name, color_list, N) + + +class RasterPlotMixin: + def plot( + self, + cmap=None, + norm=None, + figsize=None, + out_shape=(500, 500), + title_fontsize=8, + label_fontsize=6, + legend_fontsize=6, + names=None, + fig_kwds=None, + legend_kwds=None, + subplots_kwds=None, + ): + """Plot a Raster object as a raster matrix + + Parameters + ---------- + cmap : str (opt), default=None + Specify a single cmap to apply to all of the RasterLayers. + This overides the cmap attribute of each RasterLayer. + + norm : matplotlib.colors.Normalize (opt), default=None + A matplotlib.colors.Normalize to apply to all of the + RasterLayers. This overides the norm attribute of each + RasterLayer. + + figsize : tuple (opt), default=None + Size of the resulting matplotlib.figure.Figure. + + out_shape : tuple, default=(500, 500) + Number of rows, cols to read from the raster datasets for + plotting. + + title_fontsize : any number, default=8 + Size in pts of titles. + + label_fontsize : any number, default=6 + Size in pts of axis ticklabels. + + legend_fontsize : any number, default=6 + Size in pts of legend ticklabels. + + names : list (opt), default=None + Optionally supply a list of names for each RasterLayer to + override the default layer names for the titles. + + fig_kwds : dict (opt), default=None + Additional arguments to pass to the + matplotlib.pyplot.figure call when creating the figure + object. + + legend_kwds : dict (opt), default=None + Additional arguments to pass to the + matplotlib.pyplot.colorbar call when creating the colorbar + object. + + subplots_kwds : dict (opt), default=None + Additional arguments to pass to the + matplotlib.pyplot.subplots_adjust function. These are used to + control the spacing and position of each subplot, and can + include{left=None, bottom=None, right=None, top=None, + wspace=None, hspace=None}. + + Returns + ------- + axs : numpy.ndarray + array of matplotlib.axes._subplots.AxesSubplot or a single + matplotlib.axes._subplots.AxesSubplot if Raster object + contains only a single layer. + """ + + # some checks + if norm: + if not isinstance(norm, mpl.colors.Normalize): + raise AttributeError( + "norm argument should be a matplotlib.colors.Normalize object" + ) + + if cmap: + cmaps = [cmap for i in self.iloc] + else: + cmaps = [i.cmap for i in self.iloc] + + if norm: + norms = [norm for i in self.iloc] + else: + norms = [i.norm for i in self.iloc] + + if names is None: + names = self.names + else: + if len(names) != self.count: + raise AttributeError( + "arguments 'names' needs to be the same length as the number of " + "RasterLayer objects " + ) + + if fig_kwds is None: + fig_kwds = {} + + if legend_kwds is None: + legend_kwds = {} + + if subplots_kwds is None: + subplots_kwds = {} + + if figsize: + fig_kwds["figsize"] = figsize + + # estimate required number of rows and columns in figure + rows = int(np.sqrt(self.count)) + cols = int(math.ceil(np.sqrt(self.count))) + + if rows * cols < self.count: + rows += 1 + + fig, axs = plt.subplots(rows, cols, **fig_kwds) + + # axs.flat is an iterator over the row-order flattened axs array + if isinstance(axs, np.ndarray): + for ax, n, cmap, norm, name in zip( + axs.flat, range(self.count), cmaps, norms, names + ): + + arr = self.iloc[n].read(masked=True, out_shape=out_shape) + ax.set_title(name, fontsize=title_fontsize, y=1.00) + + im = ax.imshow( + arr, + extent=[ + self.bounds.left, + self.bounds.right, + self.bounds.bottom, + self.bounds.top, + ], + cmap=cmap, + norm=norm, + ) + + divider = make_axes_locatable(ax) + + if "orientation" not in legend_kwds.keys(): + legend_kwds["orientation"] = "vertical" + + if legend_kwds["orientation"] == "vertical": + legend_pos = "right" + + elif legend_kwds["orientation"] == "horizontal": + legend_pos = "bottom" + + cax = divider.append_axes(legend_pos, size="10%", pad=0.1) + cbar = plt.colorbar(im, cax=cax, **legend_kwds) + cbar.ax.tick_params(labelsize=legend_fontsize) + + # hide tick labels by default when multiple rows or cols + ax.axes.get_xaxis().set_ticklabels([]) + ax.axes.get_yaxis().set_ticklabels([]) + + # show y-axis tick labels on first subplot + if n == 0 and rows > 1: + ticks_loc = ax.get_yticks().tolist() + ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) + ax.set_yticklabels( + ax.yaxis.get_majorticklocs().astype("int"), + fontsize=label_fontsize, + ) + + if n == 0 and rows == 1: + ticks_loc = ax.get_xticks().tolist() + ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) + ax.set_xticklabels( + ax.xaxis.get_majorticklocs().astype("int"), + fontsize=label_fontsize, + ) + + ticks_loc = ax.get_yticks().tolist() + ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) + ax.set_yticklabels( + ax.yaxis.get_majorticklocs().astype("int"), + fontsize=label_fontsize, + ) + + if rows > 1 and n == (rows * cols) - cols: + ticks_loc = ax.get_xticks().tolist() + ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc)) + ax.set_xticklabels( + ax.xaxis.get_majorticklocs().astype("int"), + fontsize=label_fontsize, + ) + + for ax in axs.flat[axs.size - 1 : self.count - 1 : -1]: + ax.set_visible(False) + + plt.subplots_adjust(**subplots_kwds) + + else: + arr = self.iloc[0].read(masked=True, out_shape=out_shape) + cmap = cmaps[0] + norm = norms[0] + axs.set_title(list(names)[0], fontsize=title_fontsize, y=1.00) + im = axs.imshow( + arr, + extent=[ + self.bounds.left, + self.bounds.right, + self.bounds.bottom, + self.bounds.top, + ], + cmap=cmap, + norm=norm, + ) + + divider = make_axes_locatable(axs) + + if "orientation" not in legend_kwds.keys(): + legend_kwds["orientation"] = "vertical" + + if legend_kwds["orientation"] == "vertical": + legend_pos = "right" + + elif legend_kwds["orientation"] == "horizontal": + legend_pos = "bottom" + + cax = divider.append_axes(legend_pos, size="10%", pad=0.1) + cbar = plt.colorbar(im, cax=cax, **legend_kwds) + cbar.ax.tick_params(labelsize=legend_fontsize) + + return axs + + +class RasterLayerPlotMixin: + def plot( + self, + cmap=None, + norm=None, + ax=None, + cax=None, + figsize=None, + out_shape=(500, 500), + categorical=None, + legend=False, + vmin=None, + vmax=None, + fig_kwds=None, + legend_kwds=None, + ): + """Plot a RasterLayer using matplotlib.pyplot.imshow + + Parameters + ---------- + cmap : str (default None) + The name of a colormap recognized by matplotlib. + Overrides the cmap attribute of the RasterLayer. + + norm : matplotlib.colors.Normalize (opt) + A matplotlib.colors.Normalize to apply to the RasterLayer. + This overrides the norm attribute of the RasterLayer. + + ax : matplotlib.pyplot.Artist (optional, default None) + axes instance on which to draw to plot. + + cax : matplotlib.pyplot.Artist (optional, default None) + axes on which to draw the legend. + + figsize : tuple of integers (optional, default None) + Size of the matplotlib.figure.Figure. If the ax argument is + given explicitly, figsize is ignored. + + out_shape : tuple, default=(500, 500) + Number of rows, cols to read from the raster datasets for + plotting. + + categorical : bool (optional, default False) + if True then the raster values will be considered to + represent discrete values, otherwise they are considered to + represent continuous values. This overrides the + RasterLayer 'categorical' attribute. Setting the argument + categorical to True is ignored if the + RasterLayer.categorical is already True. + + legend : bool (optional, default False) + Whether to plot the legend. + + vmin, xmax : scale (optional, default None) + vmin and vmax define the data range that the colormap + covers. By default, the colormap covers the complete value + range of the supplied data. vmin, vmax are ignored if the + norm parameter is used. + + fig_kwds : dict (optional, default None) + Additional arguments to pass to the + matplotlib.pyplot.figure call when creating the figure + object. Ignored if ax is passed to the plot function. + + legend_kwds : dict (optional, default None) + Keyword arguments to pass to matplotlib.pyplot.colorbar(). + + Returns + ------- + ax : matplotlib axes instance + """ + + # some checks + if fig_kwds is None: + fig_kwds = {} + + if ax is None: + if cax is not None: + raise ValueError("'ax' can not be None if 'cax' is not.") + fig, ax = plt.subplots(figsize=figsize, **fig_kwds) + + ax.set_aspect("equal") + + if norm: + if not isinstance(norm, mpl.colors.Normalize): + raise AttributeError( + "norm argument should be a " "matplotlib.colors.Normalize object" + ) + + if cmap is None: + cmap = self.cmap + + if norm is None: + norm = self.norm + + if legend_kwds is None: + legend_kwds = {} + + arr = self.read(masked=True, out_shape=out_shape) + + if categorical is True: + if self.categorical is False: + N = np.bincount(arr) + cmap = discrete_cmap(N, base_cmap=cmap) + vmin, vmax = None, None + + im = ax.imshow( + X=arr, + extent=rasterio.plot.plotting_extent(self.ds), + cmap=cmap, + norm=norm, + vmin=vmin, + vmax=vmax, + ) + + if legend is True: + plt.colorbar(im, cax=cax, ax=ax, **legend_kwds) + + return ax diff --git a/pyspatialml/_prediction.py b/pyspatialml/_prediction.py index 5733464..765ac66 100644 --- a/pyspatialml/_prediction.py +++ b/pyspatialml/_prediction.py @@ -1,250 +1,250 @@ -import numpy as np -import pandas as pd - - -def stack_constants(flat_pixels, constants, names=None): - """Column stack any constant values into the flat_pixels array. - - Used to add additional constant features to the Raster object. - - Parameters - ---------- - flat_pixels : ndarray - 2d numpy array representing the flattened raster data in - (sample_n, band_values) format. - - constants : list-like object, 1d array, or dict - Array of constant values to be added to the flat_pixels array - as additional features. - - If a dict is passed, the dict keys must refer to names of the - features in the flat_pixels array, and the values will replace - these features with constant values. - - names : list-like object (optional, default=None) - Names of the raster layers. - """ - if isinstance(constants, (int, float)): - constants = [constants] - - if isinstance(constants, list): - constants = np.asarray(constants) - constants = np.broadcast_to( - constants, (flat_pixels.shape[0], constants.shape[0]) - ) - flat_pixels = np.column_stack((flat_pixels, constants)) - - elif isinstance(constants, dict): - - keys_not_in_raster = [i for i in constants.keys() if i not in names] - - if len(keys_not_in_raster) > 0: - raise ValueError( - "The following keys are not in the raster: {x}".format( - x=keys_not_in_raster - ) - ) - - flat_pixels = pd.DataFrame(flat_pixels, columns=names) - - for key, value in constants.items(): - flat_pixels[key] = value - - flat_pixels = flat_pixels.values - - elif isinstance(constants, np.ndarray): - raise ValueError("constants must be a list or a numpy.ndarray") - - return flat_pixels - - -def predict_output(img, estimator, constants=None, names=None): - """Prediction function for classification or regression response. - - Parameters - ---- - img : tuple (window, numpy.ndarray) - A window object, and a 3d ndarray of raster data with the - dimensions in order of (band, rows, columns). - - estimator : estimator object implementing 'fit' - The object to use to fit the data. - - constants : list-like object, 1d array, or dict - Array of constant values to be added to the flat_pixels array - as additional features. - - If a dict is passed, the dict keys must refer to names of the - features in the flat_pixels array, and the values will replace - these features with constant values. - - names : list-like object (optional, default=None) - Names of the raster layers. - - Returns - ------- - numpy.ndarray - 2d numpy array representing a single band raster containing the - classification or regression result. - """ - window, img = img - img = np.ma.masked_invalid(img) - - # reorder into rows, cols, bands(transpose) - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - - # reshape into 2D array (rows=sample_n, cols=band_values) - n_samples = rows * cols - flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) - - # create mask for NaN values - flat_pixels_mask = flat_pixels.mask.copy() - - # fill nans for prediction - flat_pixels = flat_pixels.filled(0) - - # add constants - if constants is not None: - flat_pixels = stack_constants(flat_pixels, constants, names) - - # predict and replace mask - result = estimator.predict(flat_pixels) - result = np.ma.masked_array(data=result, mask=flat_pixels_mask.any(axis=1)) - - # reshape the prediction from a 1D into 3D array [band, row, col] - result = result.reshape((1, window.height, window.width)) - - return result - - -def predict_prob(img, estimator, constants=None, names=None): - """Class probabilities function. - - Parameters - ---------- - img : tuple (window, numpy.ndarray) - A window object, and a 3d ndarray of raster data with the - dimensions in order of (band, rows, columns). - - estimator : estimator object implementing 'fit' - The object to use to fit the data. - - constants : list-like object, 1d array, or dict - Array of constant values to be added to the flat_pixels array - as additional features. - - If a dict is passed, the dict keys must refer to names of the - features in the flat_pixels array, and the values will replace - these features with constant values. - - names : list-like object (optional, default=None) - Names of the raster layers. - - Returns - ------- - numpy.ndarray - Multi band raster as a 3d numpy array containing the - probabilities associated with each class. ndarray dimensions - are in the order of (class, row, column). - """ - window, img = img - - # reorder into rows, cols, bands (transpose) - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - img = np.ma.masked_invalid(img) - mask2d = img.mask.any(axis=0) - - # then resample into 2D array (rows=sample_n, cols=band_values) - n_samples = rows * cols - flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) - - # fill mask with zeros for prediction - flat_pixels = flat_pixels.filled(0) - - # add constants - if constants is not None: - flat_pixels = stack_constants(flat_pixels, constants, names) - - # predict probabilities - result_proba = estimator.predict_proba(flat_pixels) - - # reshape class probabilities back to 3D array [class, rows, cols] - result_proba = result_proba.reshape( - (window.height, window.width, result_proba.shape[1]) - ) - - # reshape band into rasterio format [band, row, col] - result_proba = result_proba.transpose(2, 0, 1) - - # repeat mask for n_bands - mask3d = np.repeat( - a=mask2d[np.newaxis, :, :], repeats=result_proba.shape[0], axis=0 - ) - - # convert proba to masked array - result_proba = np.ma.masked_array(result_proba, mask=mask3d, fill_value=np.nan) - - return result_proba - - -def predict_multioutput(img, estimator, constants=None, names=None): - """Multi-target prediction function. - - Parameters - ---------- - img : tuple (window, numpy.ndarray) - A window object, and a 3d ndarray of raster data with the - dimensions in order of (band, rows, columns). - - estimator : estimator object implementing 'fit' - The object to use to fit the data. - - constants : list-like object, 1d array, or dict - Array of constant values to be added to the flat_pixels array - as additional features. - - If a dict is passed, the dict keys must refer to names of the - features in the flat_pixels array, and the values will replace - these features with constant values. - - names : list-like object (optional, default=None) - Names of the raster layers. - - Returns - ------- - numpy.ndarray - 3d numpy array representing the multi-target prediction result - with the dimensions in the order of (target, row, column). - """ - window, img = img - - # reorder into rows, cols, bands(transpose) - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - img = np.ma.masked_invalid(img) - mask2d = img.mask.any(axis=0) - - # reshape into 2D array (rows=sample_n, cols=band_values) - n_samples = rows * cols - flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) - flat_pixels = flat_pixels.filled(0) - - # add constants - if constants is not None: - flat_pixels = stack_constants(flat_pixels, constants, names) - - # predict probabilities - result = estimator.predict(flat_pixels) - - # reshape class probabilities back to 3D array [class, rows, cols] - result = result.reshape((window.height, window.width, result.shape[1])) - - # reshape band into rasterio format [band, row, col] - result = result.transpose(2, 0, 1) - - # repeat mask for n_bands - mask3d = np.repeat(a=mask2d[np.newaxis, :, :], repeats=result.shape[0], axis=0) - - # convert proba to masked array - result = np.ma.masked_array(result, mask=mask3d, fill_value=np.nan) - - return result +import numpy as np +import pandas as pd + + +def stack_constants(flat_pixels, constants, names=None): + """Column stack any constant values into the flat_pixels array. + + Used to add additional constant features to the Raster object. + + Parameters + ---------- + flat_pixels : ndarray + 2d numpy array representing the flattened raster data in + (sample_n, band_values) format. + + constants : list-like object, 1d array, or dict + Array of constant values to be added to the flat_pixels array + as additional features. + + If a dict is passed, the dict keys must refer to names of the + features in the flat_pixels array, and the values will replace + these features with constant values. + + names : list-like object (optional, default=None) + Names of the raster layers. + """ + if isinstance(constants, (int, float)): + constants = [constants] + + if isinstance(constants, list): + constants = np.asarray(constants) + constants = np.broadcast_to( + constants, (flat_pixels.shape[0], constants.shape[0]) + ) + flat_pixels = np.column_stack((flat_pixels, constants)) + + elif isinstance(constants, dict): + + keys_not_in_raster = [i for i in constants.keys() if i not in names] + + if len(keys_not_in_raster) > 0: + raise ValueError( + "The following keys are not in the raster: {x}".format( + x=keys_not_in_raster + ) + ) + + flat_pixels = pd.DataFrame(flat_pixels, columns=names) + + for key, value in constants.items(): + flat_pixels[key] = value + + flat_pixels = flat_pixels.values + + elif isinstance(constants, np.ndarray): + raise ValueError("constants must be a list or a numpy.ndarray") + + return flat_pixels + + +def predict_output(img, estimator, constants=None, names=None): + """Prediction function for classification or regression response. + + Parameters + ---- + img : tuple (window, numpy.ndarray) + A window object, and a 3d ndarray of raster data with the + dimensions in order of (band, rows, columns). + + estimator : estimator object implementing 'fit' + The object to use to fit the data. + + constants : list-like object, 1d array, or dict + Array of constant values to be added to the flat_pixels array + as additional features. + + If a dict is passed, the dict keys must refer to names of the + features in the flat_pixels array, and the values will replace + these features with constant values. + + names : list-like object (optional, default=None) + Names of the raster layers. + + Returns + ------- + numpy.ndarray + 2d numpy array representing a single band raster containing the + classification or regression result. + """ + window, img = img + img = np.ma.masked_invalid(img) + + # reorder into rows, cols, bands(transpose) + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + + # reshape into 2D array (rows=sample_n, cols=band_values) + n_samples = rows * cols + flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) + + # create mask for NaN values + flat_pixels_mask = flat_pixels.mask.copy() + + # fill nans for prediction + flat_pixels = flat_pixels.filled(0) + + # add constants + if constants is not None: + flat_pixels = stack_constants(flat_pixels, constants, names) + + # predict and replace mask + result = estimator.predict(flat_pixels) + result = np.ma.masked_array(data=result, mask=flat_pixels_mask.any(axis=1)) + + # reshape the prediction from a 1D into 3D array [band, row, col] + result = result.reshape((1, window.height, window.width)) + + return result + + +def predict_prob(img, estimator, constants=None, names=None): + """Class probabilities function. + + Parameters + ---------- + img : tuple (window, numpy.ndarray) + A window object, and a 3d ndarray of raster data with the + dimensions in order of (band, rows, columns). + + estimator : estimator object implementing 'fit' + The object to use to fit the data. + + constants : list-like object, 1d array, or dict + Array of constant values to be added to the flat_pixels array + as additional features. + + If a dict is passed, the dict keys must refer to names of the + features in the flat_pixels array, and the values will replace + these features with constant values. + + names : list-like object (optional, default=None) + Names of the raster layers. + + Returns + ------- + numpy.ndarray + Multi band raster as a 3d numpy array containing the + probabilities associated with each class. ndarray dimensions + are in the order of (class, row, column). + """ + window, img = img + + # reorder into rows, cols, bands (transpose) + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + img = np.ma.masked_invalid(img) + mask2d = img.mask.any(axis=0) + + # then resample into 2D array (rows=sample_n, cols=band_values) + n_samples = rows * cols + flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) + + # fill mask with zeros for prediction + flat_pixels = flat_pixels.filled(0) + + # add constants + if constants is not None: + flat_pixels = stack_constants(flat_pixels, constants, names) + + # predict probabilities + result_proba = estimator.predict_proba(flat_pixels) + + # reshape class probabilities back to 3D array [class, rows, cols] + result_proba = result_proba.reshape( + (window.height, window.width, result_proba.shape[1]) + ) + + # reshape band into rasterio format [band, row, col] + result_proba = result_proba.transpose(2, 0, 1) + + # repeat mask for n_bands + mask3d = np.repeat( + a=mask2d[np.newaxis, :, :], repeats=result_proba.shape[0], axis=0 + ) + + # convert proba to masked array + result_proba = np.ma.masked_array(result_proba, mask=mask3d, fill_value=np.nan) + + return result_proba + + +def predict_multioutput(img, estimator, constants=None, names=None): + """Multi-target prediction function. + + Parameters + ---------- + img : tuple (window, numpy.ndarray) + A window object, and a 3d ndarray of raster data with the + dimensions in order of (band, rows, columns). + + estimator : estimator object implementing 'fit' + The object to use to fit the data. + + constants : list-like object, 1d array, or dict + Array of constant values to be added to the flat_pixels array + as additional features. + + If a dict is passed, the dict keys must refer to names of the + features in the flat_pixels array, and the values will replace + these features with constant values. + + names : list-like object (optional, default=None) + Names of the raster layers. + + Returns + ------- + numpy.ndarray + 3d numpy array representing the multi-target prediction result + with the dimensions in the order of (target, row, column). + """ + window, img = img + + # reorder into rows, cols, bands(transpose) + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + img = np.ma.masked_invalid(img) + mask2d = img.mask.any(axis=0) + + # reshape into 2D array (rows=sample_n, cols=band_values) + n_samples = rows * cols + flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) + flat_pixels = flat_pixels.filled(0) + + # add constants + if constants is not None: + flat_pixels = stack_constants(flat_pixels, constants, names) + + # predict probabilities + result = estimator.predict(flat_pixels) + + # reshape class probabilities back to 3D array [class, rows, cols] + result = result.reshape((window.height, window.width, result.shape[1])) + + # reshape band into rasterio format [band, row, col] + result = result.transpose(2, 0, 1) + + # repeat mask for n_bands + mask3d = np.repeat(a=mask2d[np.newaxis, :, :], repeats=result.shape[0], axis=0) + + # convert proba to masked array + result = np.ma.masked_array(result, mask=mask3d, fill_value=np.nan) + + return result diff --git a/pyspatialml/_rasterstats.py b/pyspatialml/_rasterstats.py index 9cba3f1..8a4d4ed 100644 --- a/pyspatialml/_rasterstats.py +++ b/pyspatialml/_rasterstats.py @@ -1,137 +1,137 @@ -import numpy as np - - -class RasterStatsMixin: - def _stats(self, max_pixels): - rel_width = self.shape[1] / max_pixels - - if rel_width > 1: - col_scaling = round(max_pixels / rel_width) - row_scaling = max_pixels - col_scaling - else: - col_scaling = round(max_pixels * rel_width) - row_scaling = max_pixels - col_scaling - - out_shape = (row_scaling, col_scaling) - arr = self.read(masked=True, out_shape=out_shape) - return arr.reshape((arr.shape[0], arr.shape[1] * arr.shape[2])) - - def min(self, max_pixels=10000): - arr = self._stats(max_pixels) - return np.nanmin(arr, axis=1).data - - def max(self, max_pixels=10000): - arr = self._stats(max_pixels) - return np.nanmax(arr, axis=1).data - - def mean(self, max_pixels=10000): - arr = self._stats(max_pixels) - return np.nanmean(arr, axis=1).data - - def median(self, max_pixels=10000): - arr = self._stats(max_pixels) - return np.nanmedian(arr, axis=1).data - - def stddev(self, max_pixels=10000): - arr = self._stats(max_pixels) - return np.nanstd(arr, axis=1).data - - -class RasterLayerStatsMixin: - def _stats(self, max_pixels): - """Take a sample of pixels from which to derive per-band - statistics.""" - - rel_width = self.shape[1] / max_pixels - - if rel_width > 1: - col_scaling = round(max_pixels / rel_width) - row_scaling = max_pixels - col_scaling - else: - col_scaling = round(max_pixels * rel_width) - row_scaling = max_pixels - col_scaling - - out_shape = (row_scaling, col_scaling) - arr = self.read(masked=True, out_shape=out_shape) - arr = arr.flatten() - return arr - - def min(self, max_pixels=10000): - """Minimum value. - - Parameters - ---------- - max_pixels : int - Number of pixels used to inform statistical estimate. - - Returns - ------- - numpy.float32 - The minimum value of the object - """ - arr = self._stats(max_pixels) - return np.nanmin(arr) - - def max(self, max_pixels=10000): - """Maximum value. - - Parameters - ---------- - max_pixels : int - Number of pixels used to inform statistical estimate. - - Returns - ------- - numpy.float32 - The maximum value of the object's pixels. - """ - arr = self._stats(max_pixels) - return np.nanmax(arr) - - def mean(self, max_pixels=10000): - """Mean value - - Parameters - ---------- - max_pixels : int - Number of pixels used to inform statistical estimate. - - Returns - ------- - numpy.float32 - The mean value of the object's pixels. - """ - arr = self._stats(max_pixels) - return np.nanmean(arr) - - def median(self, max_pixels=10000): - """Median value - - Parameters - ---------- - max_pixels : int - Number of pixels used to inform statistical estimate. - - Returns - ------- - numpy.float32 - The medium value of the object's pixels. - """ - arr = self._stats(max_pixels) - return np.nanmedian(arr) - - def stddev(self, max_pixels=10000): - """Standard deviation - - Parameters - ---------- - max_pixels : int - Number of pixels used to inform statistical estimate. - - Returns - ------- - numpy.float32 - The standard deviation of the object's pixels. - """ - arr = self._stats(max_pixels) - return np.nanstd(arr) +import numpy as np + + +class RasterStatsMixin: + def _stats(self, max_pixels): + rel_width = self.shape[1] / max_pixels + + if rel_width > 1: + col_scaling = round(max_pixels / rel_width) + row_scaling = max_pixels - col_scaling + else: + col_scaling = round(max_pixels * rel_width) + row_scaling = max_pixels - col_scaling + + out_shape = (row_scaling, col_scaling) + arr = self.read(masked=True, out_shape=out_shape) + return arr.reshape((arr.shape[0], arr.shape[1] * arr.shape[2])) + + def min(self, max_pixels=10000): + arr = self._stats(max_pixels) + return np.nanmin(arr, axis=1).data + + def max(self, max_pixels=10000): + arr = self._stats(max_pixels) + return np.nanmax(arr, axis=1).data + + def mean(self, max_pixels=10000): + arr = self._stats(max_pixels) + return np.nanmean(arr, axis=1).data + + def median(self, max_pixels=10000): + arr = self._stats(max_pixels) + return np.nanmedian(arr, axis=1).data + + def stddev(self, max_pixels=10000): + arr = self._stats(max_pixels) + return np.nanstd(arr, axis=1).data + + +class RasterLayerStatsMixin: + def _stats(self, max_pixels): + """Take a sample of pixels from which to derive per-band + statistics.""" + + rel_width = self.shape[1] / max_pixels + + if rel_width > 1: + col_scaling = round(max_pixels / rel_width) + row_scaling = max_pixels - col_scaling + else: + col_scaling = round(max_pixels * rel_width) + row_scaling = max_pixels - col_scaling + + out_shape = (row_scaling, col_scaling) + arr = self.read(masked=True, out_shape=out_shape) + arr = arr.flatten() + return arr + + def min(self, max_pixels=10000): + """Minimum value. + + Parameters + ---------- + max_pixels : int + Number of pixels used to inform statistical estimate. + + Returns + ------- + numpy.float32 + The minimum value of the object + """ + arr = self._stats(max_pixels) + return np.nanmin(arr) + + def max(self, max_pixels=10000): + """Maximum value. + + Parameters + ---------- + max_pixels : int + Number of pixels used to inform statistical estimate. + + Returns + ------- + numpy.float32 + The maximum value of the object's pixels. + """ + arr = self._stats(max_pixels) + return np.nanmax(arr) + + def mean(self, max_pixels=10000): + """Mean value + + Parameters + ---------- + max_pixels : int + Number of pixels used to inform statistical estimate. + + Returns + ------- + numpy.float32 + The mean value of the object's pixels. + """ + arr = self._stats(max_pixels) + return np.nanmean(arr) + + def median(self, max_pixels=10000): + """Median value + + Parameters + ---------- + max_pixels : int + Number of pixels used to inform statistical estimate. + + Returns + ------- + numpy.float32 + The medium value of the object's pixels. + """ + arr = self._stats(max_pixels) + return np.nanmedian(arr) + + def stddev(self, max_pixels=10000): + """Standard deviation + + Parameters + ---------- + max_pixels : int + Number of pixels used to inform statistical estimate. + + Returns + ------- + numpy.float32 + The standard deviation of the object's pixels. + """ + arr = self._stats(max_pixels) + return np.nanstd(arr) diff --git a/pyspatialml/_utils.py b/pyspatialml/_utils.py index ea607f6..4335f50 100644 --- a/pyspatialml/_utils.py +++ b/pyspatialml/_utils.py @@ -1,44 +1,44 @@ -import multiprocessing -import numpy as np - - -def get_nodata_value(dtype): - """Get a nodata value based on the minimum value permissible by dtype - - Parameters - ---------- - dtype : str or dtype - dtype to return a nodata value for - - Returns - ------- - nodata : any number - A nodata value that is accomodated by the supplied dtype - """ - try: - nodata = np.iinfo(dtype).min - except ValueError: - nodata = np.finfo(dtype).min - - return nodata - - -def get_num_workers(n_jobs): - """Determine cpu count using scikit-learn convention of -1, -2 ... - - Parameters - ---------- - n_jobs : int - Number of processing cores including -1 for all cores -1, etc. - - Returns - ------- - n_jobs : int - The actual number of processing cores. - """ - n_cpus = multiprocessing.cpu_count() - - if n_jobs < 0: - n_jobs = n_cpus + n_jobs + 1 - - return n_jobs +import multiprocessing +import numpy as np + + +def get_nodata_value(dtype): + """Get a nodata value based on the minimum value permissible by dtype + + Parameters + ---------- + dtype : str or dtype + dtype to return a nodata value for + + Returns + ------- + nodata : any number + A nodata value that is accomodated by the supplied dtype + """ + try: + nodata = np.iinfo(dtype).min + except ValueError: + nodata = np.finfo(dtype).min + + return nodata + + +def get_num_workers(n_jobs): + """Determine cpu count using scikit-learn convention of -1, -2 ... + + Parameters + ---------- + n_jobs : int + Number of processing cores including -1 for all cores -1, etc. + + Returns + ------- + n_jobs : int + The actual number of processing cores. + """ + n_cpus = multiprocessing.cpu_count() + + if n_jobs < 0: + n_jobs = n_cpus + n_jobs + 1 + + return n_jobs diff --git a/pyspatialml/datasets/extracted_pixels.txt b/pyspatialml/datasets/extracted_pixels.txt index e5205a3..8cb718c 100644 --- a/pyspatialml/datasets/extracted_pixels.txt +++ b/pyspatialml/datasets/extracted_pixels.txt @@ -1,2437 +1,2437 @@ -id b1 b2 b3 b4 b5 b7 -133 59 5 94 76 80 58 89 70 -134 59 5 91 76 77 56 81 61 -135 59 5 84 70 76 62 102 65 -136 59 5 79 65 75 64 123 78 -137 59 5 77 64 70 62 128 81 -138 59 5 77 61 67 61 119 75 -139 59 5 79 61 74 64 137 86 -140 59 5 77 61 70 61 126 79 -141 59 5 78 62 68 61 121 77 -142 59 5 77 60 65 61 118 77 -143 59 5 75 60 64 60 114 72 -144 59 5 75 59 60 59 104 68 -145 59 5 81 63 72 72 110 68 -133 60 5 79 65 64 63 89 51 -134 60 5 78 66 66 61 100 56 -135 60 5 80 63 66 60 96 60 -136 60 5 76 59 62 60 90 56 -137 60 5 73 59 60 58 93 56 -138 60 5 73 56 57 58 86 52 -139 60 5 75 60 64 59 113 72 -140 60 5 78 60 63 58 113 72 -141 60 5 77 58 61 59 108 68 -142 60 5 73 57 57 56 100 63 -143 60 5 75 58 57 55 97 61 -144 60 5 73 59 57 58 98 61 -145 60 5 75 60 63 59 104 62 -133 61 5 73 59 60 65 94 58 -134 61 5 74 55 58 57 95 59 -135 61 5 72 55 54 53 84 52 -136 61 5 75 55 55 58 85 52 -137 61 5 75 55 55 58 85 52 -138 61 5 72 52 51 64 75 43 -139 61 5 72 56 58 57 85 53 -140 61 5 74 59 61 58 101 62 -141 61 5 76 57 61 59 100 59 -142 61 5 73 55 58 54 85 52 -143 61 5 71 55 52 56 81 48 -144 61 5 75 57 55 56 90 55 -145 61 5 73 57 56 54 91 55 -133 62 5 75 58 54 59 89 52 -134 62 5 70 53 52 58 83 50 -135 62 5 69 54 51 57 77 46 -136 62 5 74 53 49 59 81 47 -137 62 5 71 52 44 69 67 39 -138 62 5 68 55 45 69 65 36 -139 62 5 74 56 57 56 88 52 -140 62 5 71 55 58 59 95 56 -141 62 5 72 54 54 55 85 57 -142 62 5 71 55 51 56 79 47 -143 62 5 72 54 51 55 75 48 -144 62 5 69 51 48 53 60 35 -145 62 5 69 51 46 54 63 36 -133 63 5 74 58 55 61 95 57 -134 63 5 70 56 52 68 78 47 -135 63 5 69 54 47 73 76 43 -136 63 5 72 55 46 71 73 40 -137 63 5 72 56 48 72 67 36 -138 63 5 68 55 47 72 71 38 -139 63 5 71 54 56 58 83 49 -140 63 5 71 54 56 58 90 54 -141 63 5 70 55 52 56 87 54 -142 63 5 71 52 48 53 71 42 -143 63 5 68 51 46 58 67 38 -144 63 5 70 56 50 64 73 40 -145 63 5 68 49 42 59 58 32 -134 64 5 74 62 64 73 109 66 -135 64 5 73 62 57 84 103 59 -136 64 5 73 60 52 84 102 54 -137 64 5 72 59 52 75 90 48 -138 64 5 68 55 47 72 71 38 -139 64 5 70 54 51 63 84 50 -140 64 5 73 56 57 58 93 59 -141 64 5 70 56 54 62 85 48 -142 64 5 72 54 52 65 72 41 -143 64 5 70 55 47 72 79 44 -144 64 5 71 61 57 75 93 53 -145 64 5 71 51 48 60 64 36 -134 65 5 80 66 74 74 111 69 -135 65 5 79 69 69 80 110 64 -136 65 5 74 63 61 80 112 62 -137 65 5 73 58 55 73 100 57 -138 65 5 70 57 52 71 79 43 -139 65 5 74 58 62 65 91 54 -140 65 5 75 58 61 62 102 62 -141 65 5 73 56 60 65 98 58 -142 65 5 73 57 55 67 93 55 -143 65 5 72 57 51 74 98 55 -144 65 5 71 57 55 68 90 53 -145 65 5 72 54 52 60 74 41 -138 80 7 87 75 80 71 107 73 -139 80 7 96 84 95 77 128 88 -140 80 7 94 86 99 78 138 89 -141 80 7 102 91 107 75 127 86 -138 81 7 98 88 96 79 139 98 -139 81 7 110 97 115 81 152 122 -140 81 7 125 115 135 76 139 125 -141 81 7 100 91 101 75 109 83 -138 82 7 94 80 89 74 136 99 -139 82 7 104 89 98 71 142 116 -140 82 7 135 129 148 78 179 176 -141 82 7 118 111 128 71 143 137 -138 83 7 86 74 74 81 119 66 -139 83 7 100 88 97 76 125 96 -140 83 7 131 125 147 78 183 178 -141 83 7 132 122 141 74 172 167 -138 84 7 112 100 110 88 132 101 -139 84 7 117 110 122 82 127 105 -140 84 7 130 123 144 79 182 177 -141 84 7 124 112 133 68 173 174 -146 84 7 95 85 95 62 116 95 -147 84 7 116 108 129 69 137 133 -148 84 7 126 118 144 73 143 132 -149 84 7 109 96 116 64 128 116 -150 84 7 121 108 124 74 107 83 -145 85 7 93 76 85 62 105 77 -146 85 7 113 97 114 62 121 112 -147 85 7 122 111 134 72 139 133 -148 85 7 122 116 134 72 140 131 -149 85 7 115 102 121 64 125 112 -150 85 7 133 122 141 73 109 89 -145 86 7 116 104 118 68 146 131 -146 86 7 125 111 127 67 144 140 -147 86 7 122 112 131 69 138 132 -148 86 7 117 106 126 65 115 108 -149 86 7 119 109 121 65 124 111 -150 86 7 114 99 109 61 108 91 -403 114 1 97 83 90 58 85 74 -404 114 1 99 81 88 51 77 65 -402 115 1 98 88 93 57 100 90 -403 115 1 99 86 91 57 90 74 -404 115 1 93 76 75 57 84 69 -405 115 1 83 67 68 55 85 66 -402 116 1 129 117 129 69 103 91 -403 116 1 97 85 88 64 93 73 -404 116 1 106 90 98 64 99 76 -405 116 1 105 94 100 64 103 88 -406 116 1 112 97 109 65 101 92 -407 116 1 104 94 109 60 92 80 -408 116 1 112 102 119 62 101 88 -401 117 1 124 105 116 54 120 117 -402 117 1 157 139 156 80 165 156 -403 117 1 94 87 96 78 115 82 -404 117 1 103 87 97 63 101 83 -405 117 1 118 105 117 69 106 88 -406 117 1 108 92 101 63 100 80 -407 117 1 110 102 120 68 127 102 -408 117 1 108 102 120 63 108 90 -409 117 1 110 98 111 58 116 103 -410 117 1 106 93 98 51 69 61 -400 118 1 92 77 76 57 72 54 -401 118 1 99 81 82 52 86 81 -402 118 1 117 104 116 61 128 128 -403 118 1 102 94 110 73 123 100 -404 118 1 83 70 73 60 92 71 -405 118 1 103 89 106 65 109 88 -406 118 1 84 66 68 49 73 64 -407 118 1 99 87 96 56 89 80 -408 118 1 111 99 110 57 93 87 -409 118 1 111 96 107 53 86 77 -410 118 1 104 89 90 46 88 83 -411 118 1 108 99 114 57 102 91 -412 118 1 99 86 93 56 83 76 -399 119 1 72 60 50 62 68 45 -400 119 1 81 68 60 67 80 59 -401 119 1 102 94 105 71 114 92 -402 119 1 102 94 105 71 114 92 -403 119 1 97 88 101 65 115 94 -404 119 1 97 83 89 60 90 61 -405 119 1 113 103 118 69 105 89 -406 119 1 94 78 85 55 87 69 -407 119 1 121 110 132 69 141 125 -408 119 1 149 136 154 77 150 149 -409 119 1 134 117 128 61 121 120 -410 119 1 96 76 77 38 58 55 -411 119 1 95 82 92 51 99 80 -412 119 1 109 96 113 70 99 86 -413 119 1 104 87 98 61 89 74 -399 120 1 83 68 71 66 63 39 -400 120 1 86 71 69 76 83 50 -401 120 1 96 87 95 75 109 76 -402 120 1 97 86 93 62 102 79 -403 120 1 98 85 95 66 98 79 -404 120 1 113 101 113 70 112 99 -405 120 1 98 85 96 59 93 81 -406 120 1 141 126 145 74 143 135 -407 120 1 159 147 168 81 154 147 -408 120 1 135 124 139 68 126 121 -409 120 1 107 87 95 55 90 82 -410 120 1 92 74 84 51 81 69 -411 120 1 110 99 117 66 107 95 -412 120 1 106 100 122 69 120 103 -413 120 1 100 87 97 55 95 81 -398 121 1 94 78 79 64 76 60 -399 121 1 95 83 84 65 80 64 -400 121 1 99 86 91 69 94 61 -401 121 1 103 92 102 68 106 81 -402 121 1 110 102 117 64 110 98 -403 121 1 114 105 117 73 124 100 -404 121 1 104 95 105 66 104 91 -405 121 1 102 87 92 55 95 87 -406 121 1 114 99 111 58 111 111 -407 121 1 128 112 128 61 107 104 -408 121 1 124 112 126 61 91 89 -409 121 1 104 90 94 59 88 81 -410 121 1 103 87 99 58 98 84 -411 121 1 110 97 112 62 105 94 -412 121 1 97 85 95 53 85 75 -397 122 1 102 90 93 75 95 68 -398 122 1 106 91 102 74 94 69 -399 122 1 111 98 111 68 97 80 -400 122 1 125 116 125 71 100 78 -401 122 1 107 95 104 64 94 76 -402 122 1 114 109 126 67 123 110 -403 122 1 121 115 133 75 130 108 -404 122 1 109 100 111 70 116 100 -405 122 1 98 86 92 59 86 75 -406 122 1 94 77 82 44 79 73 -407 122 1 96 79 84 43 88 80 -408 122 1 110 96 109 56 109 102 -409 122 1 109 96 109 58 99 92 -410 122 1 96 78 81 54 83 72 -411 122 1 104 88 97 56 91 78 -397 123 1 128 118 133 76 115 95 -398 123 1 117 102 118 70 103 82 -399 123 1 116 103 113 69 100 82 -400 123 1 128 118 131 71 97 86 -401 123 1 108 98 114 61 97 84 -402 123 1 118 112 131 67 110 96 -403 123 1 115 109 122 67 122 101 -404 123 1 104 99 113 71 107 83 -405 123 1 94 77 84 58 87 73 -406 123 1 99 87 96 55 81 65 -407 123 1 125 115 134 71 111 93 -408 123 1 132 122 140 76 134 118 -409 123 1 109 99 114 60 110 101 -410 123 1 102 84 95 51 86 74 -411 123 1 107 90 102 55 100 88 -397 124 1 112 94 103 54 95 84 -398 124 1 107 91 102 62 101 88 -399 124 1 113 102 114 68 114 98 -400 124 1 120 116 129 70 124 109 -401 124 1 126 122 141 72 131 113 -402 124 1 128 121 142 72 125 105 -403 124 1 121 117 136 74 114 94 -404 124 1 99 87 95 67 101 78 -405 124 1 91 74 81 63 107 80 -406 124 1 100 87 99 59 101 79 -407 124 1 119 109 126 67 121 106 -408 124 1 122 116 133 72 134 120 -409 124 1 102 95 109 58 106 95 -410 124 1 107 94 105 54 102 94 -399 125 1 106 102 118 68 116 102 -400 125 1 116 120 147 80 137 115 -401 125 1 126 123 147 78 131 108 -402 125 1 121 109 131 72 132 105 -403 125 1 121 117 136 74 114 94 -404 125 1 91 82 89 66 95 73 -405 125 1 81 68 67 61 96 71 -406 125 1 89 73 81 55 95 74 -407 125 1 105 94 107 60 113 100 -408 125 1 121 114 134 70 128 117 -409 125 1 110 100 119 61 107 95 -401 126 1 91 78 87 68 94 70 -402 126 1 89 75 76 66 97 74 -403 126 1 88 78 82 57 93 71 -404 126 1 93 82 86 60 93 76 -405 126 1 101 88 100 61 100 85 -406 126 1 110 98 115 62 113 98 -407 126 1 112 103 122 63 120 105 -408 126 1 111 98 115 59 113 98 -402 127 1 91 75 79 66 107 71 -403 127 1 95 84 89 71 113 90 -404 127 1 96 86 89 81 123 96 -405 127 1 114 102 116 68 126 111 -406 127 1 117 102 120 58 110 108 -407 127 1 120 107 126 64 117 103 -408 127 1 142 129 151 76 129 112 -404 128 1 88 77 79 86 114 80 -405 128 1 107 94 104 71 109 94 -406 128 1 106 89 100 55 94 92 -407 128 1 115 102 117 69 134 119 -406 129 1 92 76 77 66 108 81 -352 134 3 79 66 71 65 122 77 -353 134 3 82 67 77 73 131 83 -354 134 3 79 65 73 80 127 77 -355 134 3 77 65 64 80 109 63 -352 135 3 78 65 72 66 124 77 -353 135 3 81 68 78 77 137 84 -354 135 3 78 66 70 82 119 71 -355 135 3 71 57 50 76 79 45 -356 135 3 68 52 46 69 62 36 -357 135 3 74 59 56 72 85 50 -358 135 3 78 68 69 79 120 69 -359 135 3 83 69 74 76 124 73 -360 135 3 81 70 74 82 123 75 -352 136 3 81 67 78 78 138 84 -353 136 3 81 69 74 83 135 83 -354 136 3 75 63 56 82 99 58 -355 136 3 69 55 46 77 69 36 -356 136 3 68 52 43 73 56 30 -357 136 3 72 56 49 74 79 45 -358 136 3 78 68 69 79 120 69 -359 136 3 81 71 75 81 129 76 -360 136 3 85 75 78 82 123 73 -361 136 3 84 81 90 83 113 75 -362 136 3 84 83 98 88 126 89 -363 136 3 81 77 94 90 127 80 -352 137 3 81 68 72 87 121 75 -353 137 3 76 63 60 78 100 60 -354 137 3 71 56 46 76 75 40 -355 137 3 70 55 46 77 67 33 -356 137 3 67 54 45 75 62 34 -357 137 3 71 58 49 75 67 37 -358 137 3 78 68 69 80 124 73 -359 137 3 82 72 74 78 134 82 -360 137 3 88 81 90 77 137 93 -361 137 3 91 86 101 80 136 99 -362 137 3 83 76 85 83 122 85 -363 137 3 85 83 100 85 129 89 -352 138 3 72 58 52 79 81 47 -353 138 3 72 57 48 76 81 45 -354 138 3 72 55 47 80 74 38 -355 138 3 72 54 47 78 63 33 -356 138 3 69 53 44 77 56 28 -357 138 3 69 56 48 79 59 32 -358 138 3 76 66 59 80 99 55 -359 138 3 80 70 73 79 128 77 -360 138 3 84 76 86 80 126 87 -361 138 3 87 81 92 86 132 90 -362 138 3 83 75 82 80 134 84 -363 138 3 85 79 90 86 128 85 -352 139 3 73 57 50 78 73 41 -353 139 3 72 57 49 79 81 41 -354 139 3 71 57 50 79 75 37 -355 139 3 70 56 46 78 62 35 -356 139 3 69 58 47 80 61 35 -357 139 3 74 62 60 83 82 44 -358 139 3 76 64 59 83 87 50 -359 139 3 76 68 66 94 112 60 -360 139 3 77 69 60 96 106 64 -361 139 3 76 69 58 107 102 55 -362 139 3 78 70 68 98 120 70 -363 139 3 89 84 95 75 143 99 -352 140 3 69 55 51 77 79 42 -353 140 3 71 56 48 76 65 35 -354 140 3 73 55 48 79 62 34 -355 140 3 69 58 52 85 81 45 -356 140 3 78 67 69 88 123 72 -357 140 3 83 70 76 82 139 83 -358 140 3 76 68 66 90 111 61 -359 140 3 81 71 67 91 117 67 -360 140 3 80 69 69 100 111 59 -361 140 3 79 71 66 107 103 59 -362 140 3 85 74 75 85 128 79 -363 140 3 80 72 72 73 140 89 -352 141 3 73 58 55 81 92 50 -353 141 3 71 58 50 85 81 44 -354 141 3 73 60 50 91 77 40 -355 141 3 75 64 57 93 97 54 -356 141 3 81 71 73 85 137 80 -357 141 3 85 71 73 80 142 84 -358 141 3 78 68 65 90 113 66 -359 141 3 79 67 66 95 114 62 -360 141 3 85 72 74 93 133 77 -361 141 3 77 70 63 109 106 58 -362 141 3 80 73 70 89 119 74 -363 141 3 85 74 75 85 128 79 -352 142 3 74 63 56 96 104 56 -353 142 3 71 60 48 110 97 49 -354 142 3 70 59 47 111 88 41 -355 142 3 72 62 53 99 97 50 -356 142 3 79 68 64 89 122 71 -357 142 3 82 71 77 81 139 83 -358 142 3 78 68 67 86 123 75 -359 142 3 79 67 63 95 110 57 -360 142 3 85 72 76 91 132 77 -361 142 3 79 69 59 108 104 55 -362 142 3 82 76 75 95 119 72 -363 142 3 89 80 100 67 117 83 -352 143 3 76 64 61 91 105 58 -353 143 3 77 62 55 112 102 53 -354 143 3 73 60 47 117 91 42 -355 143 3 70 60 47 110 88 40 -356 143 3 76 64 58 101 100 55 -357 143 3 78 66 61 86 115 66 -358 143 3 82 70 73 81 121 75 -359 143 3 76 64 63 86 100 56 -360 143 3 81 71 69 90 116 67 -361 143 3 77 67 60 107 95 47 -362 143 3 82 74 69 102 109 62 -363 143 3 106 105 128 84 158 106 -352 144 3 77 66 65 77 114 67 -353 144 3 78 66 64 79 109 61 -354 144 3 76 61 56 91 97 56 -355 144 3 74 62 51 109 86 49 -356 144 3 77 64 58 98 78 46 -357 144 3 79 65 59 76 81 51 -358 144 3 78 61 62 63 106 66 -359 144 3 78 62 58 65 91 58 -360 144 3 81 72 72 81 104 65 -361 144 3 83 71 65 98 100 57 -362 144 3 80 73 66 99 112 65 -363 144 3 93 89 100 85 149 95 -352 145 3 77 67 67 79 113 69 -353 145 3 74 65 63 83 104 61 -354 145 3 79 65 64 89 102 60 -355 145 3 77 64 57 92 89 55 -356 145 3 79 64 59 64 63 47 -357 145 3 89 73 71 50 63 55 -358 145 3 78 62 63 65 96 63 -359 145 3 79 67 70 71 109 71 -360 145 3 87 74 76 87 120 75 -361 145 3 81 72 73 99 117 71 -362 145 3 84 76 76 87 137 88 -363 145 3 86 78 82 83 128 78 -352 146 3 85 73 73 72 100 67 -353 146 3 81 68 68 87 109 63 -354 146 3 78 67 62 87 95 49 -355 146 3 81 63 57 50 60 37 -356 146 3 91 71 66 39 57 48 -357 146 3 89 73 75 54 78 62 -358 146 3 79 66 68 62 108 71 -359 146 3 81 72 77 86 131 82 -360 146 3 81 72 77 86 131 82 -361 146 3 79 71 70 97 131 75 -362 146 3 85 74 84 77 145 94 -363 146 3 86 79 86 78 137 84 -352 147 3 86 73 76 90 100 70 -353 147 3 77 65 60 83 96 60 -354 147 3 76 65 57 67 85 51 -355 147 3 77 61 52 70 71 40 -356 147 3 80 68 60 66 74 48 -357 147 3 82 67 69 70 83 49 -358 147 3 79 66 63 68 88 61 -359 147 3 91 77 83 71 115 84 -360 147 3 87 77 79 85 122 85 -361 147 3 84 76 80 86 135 80 -362 147 3 84 74 83 74 139 88 -363 147 3 82 78 84 74 138 86 -352 148 3 88 75 76 92 99 57 -353 148 3 85 69 64 63 70 43 -354 148 3 81 65 61 58 68 47 -355 148 3 72 59 52 75 82 46 -356 148 3 74 62 54 65 81 50 -357 148 3 82 67 69 70 83 49 -358 148 3 86 70 67 66 85 62 -359 148 3 108 90 99 60 100 87 -360 148 3 110 93 103 66 101 88 -361 148 3 86 76 75 98 108 63 -362 148 3 84 73 73 92 130 79 -363 148 3 85 75 85 74 139 86 -352 149 3 100 84 84 68 97 79 -353 149 3 91 73 70 58 70 55 -354 149 3 80 63 60 69 82 55 -355 149 3 70 56 50 66 84 49 -356 149 3 73 59 52 61 81 48 -357 149 3 80 64 64 67 89 60 -358 149 3 82 66 66 55 86 63 -359 149 3 93 79 81 52 89 71 -360 149 3 107 87 93 64 93 73 -361 149 3 79 67 60 94 85 44 -362 149 3 76 67 61 101 110 61 -363 149 3 84 71 81 81 134 85 -264 169 5 71 50 43 49 65 40 -265 169 5 69 53 44 53 68 39 -266 169 5 69 50 46 57 72 39 -267 169 5 68 50 44 56 54 32 -268 169 5 70 52 48 51 57 35 -269 169 5 76 63 56 65 78 49 -270 169 5 75 62 61 67 98 59 -271 169 5 74 57 56 67 87 49 -272 169 5 72 55 50 60 66 38 -273 169 5 74 58 58 64 98 58 -274 169 5 74 59 59 63 100 63 -102 170 1 82 64 57 75 75 48 -103 170 1 87 72 74 64 90 68 -104 170 1 104 89 96 54 92 80 -264 170 5 70 50 41 48 56 35 -265 170 5 68 51 43 54 64 37 -266 170 5 68 56 49 56 70 40 -267 170 5 68 50 43 50 52 35 -268 170 5 70 53 46 57 64 38 -269 170 5 70 56 52 60 78 46 -270 170 5 71 52 48 58 81 48 -271 170 5 73 54 48 58 72 41 -272 170 5 70 55 57 61 89 54 -273 170 5 78 58 65 61 104 64 -274 170 5 74 60 64 60 100 63 -100 171 1 97 79 78 60 71 50 -101 171 1 95 76 77 59 76 54 -102 171 1 112 96 103 69 97 80 -103 171 1 99 82 87 58 94 75 -104 171 1 103 89 100 61 94 78 -264 171 5 68 50 44 53 62 34 -265 171 5 68 53 50 62 75 41 -266 171 5 71 56 53 63 76 45 -267 171 5 69 52 48 55 60 37 -268 171 5 68 49 41 56 48 25 -269 171 5 68 52 45 62 58 31 -270 171 5 69 50 44 59 62 35 -271 171 5 72 53 49 61 72 39 -272 171 5 73 56 55 60 90 55 -273 171 5 76 58 61 59 99 62 -274 171 5 70 56 59 58 93 54 -294 171 6 74 59 61 63 110 70 -295 171 6 73 58 59 64 105 65 -296 171 6 75 61 60 66 116 71 -297 171 6 78 60 62 66 115 71 -298 171 6 75 59 56 64 103 63 -299 171 6 75 60 62 63 108 65 -300 171 6 75 59 63 66 101 61 -301 171 6 74 57 56 63 94 55 -98 172 1 99 80 86 57 93 68 -99 172 1 99 79 79 45 63 54 -100 172 1 100 75 78 37 57 46 -101 172 1 97 73 78 48 62 45 -102 172 1 111 100 108 68 101 88 -103 172 1 111 97 107 65 98 86 -104 172 1 100 87 96 63 94 81 -264 172 5 69 53 52 60 77 44 -265 172 5 74 59 63 69 94 56 -266 172 5 71 56 53 63 76 45 -267 172 5 73 58 54 59 76 49 -268 172 5 68 50 40 54 49 27 -269 172 5 67 48 42 61 59 33 -270 172 5 66 51 45 60 62 33 -271 172 5 70 54 50 64 70 37 -272 172 5 72 56 55 62 84 51 -273 172 5 74 58 64 60 98 60 -274 172 5 72 58 60 60 93 54 -293 172 6 75 62 62 64 115 72 -294 172 6 74 59 58 62 115 73 -295 172 6 75 58 59 61 107 65 -296 172 6 76 58 62 62 115 71 -297 172 6 73 59 63 60 111 72 -298 172 6 75 61 65 59 117 73 -299 172 6 77 59 62 64 113 70 -300 172 6 75 58 63 62 108 68 -301 172 6 81 64 71 58 133 92 -96 173 1 114 105 122 76 120 93 -97 173 1 134 129 148 80 132 107 -98 173 1 131 114 139 71 119 98 -99 173 1 116 103 116 61 94 80 -100 173 1 98 78 84 42 65 54 -101 173 1 95 71 72 39 59 51 -102 173 1 111 100 108 68 101 88 -103 173 1 109 97 108 65 99 91 -104 173 1 98 82 88 57 96 84 -264 173 5 73 57 54 65 86 53 -265 173 5 77 63 69 72 109 66 -266 173 5 73 58 58 66 88 55 -267 173 5 76 57 55 59 81 54 -268 173 5 68 53 44 52 62 36 -269 173 5 66 49 42 60 60 35 -270 173 5 68 51 45 59 62 32 -271 173 5 69 55 52 60 77 43 -272 173 5 73 57 58 63 95 56 -273 173 5 75 60 63 63 105 62 -274 173 5 74 61 65 63 112 69 -293 173 6 74 62 63 65 117 70 -294 173 6 75 60 65 64 122 79 -295 173 6 75 58 62 60 110 74 -296 173 6 76 59 63 60 115 71 -297 173 6 77 64 69 62 125 82 -298 173 6 75 63 69 60 114 75 -299 173 6 79 65 73 63 126 84 -300 173 6 77 66 74 61 136 93 -301 173 6 77 65 79 57 141 102 -94 174 1 135 119 140 70 182 189 -95 174 1 113 95 110 62 116 108 -96 174 1 124 119 136 78 146 115 -97 174 1 149 154 185 103 187 154 -98 174 1 155 161 203 110 186 156 -99 174 1 149 152 189 104 178 150 -100 174 1 111 102 113 69 100 79 -101 174 1 95 76 79 50 71 54 -102 174 1 95 81 87 58 90 64 -103 174 1 107 94 107 66 105 89 -104 174 1 109 93 107 59 89 82 -105 174 1 104 90 99 56 90 79 -264 174 5 75 58 58 64 85 53 -265 174 5 76 61 63 66 95 59 -266 174 5 77 63 68 67 109 68 -267 174 5 75 57 60 57 89 57 -268 174 5 71 56 53 54 76 46 -269 174 5 69 52 48 61 75 46 -270 174 5 70 53 44 59 65 35 -271 174 5 69 54 52 59 68 39 -272 174 5 73 56 57 61 91 53 -273 174 5 74 60 64 63 102 60 -274 174 5 76 61 68 63 118 74 -293 174 6 75 61 61 66 113 68 -294 174 6 74 60 61 63 112 70 -295 174 6 75 57 64 61 115 78 -296 174 6 77 63 70 62 126 83 -297 174 6 78 64 70 60 130 87 -298 174 6 79 66 73 59 111 75 -299 174 6 78 65 73 59 111 77 -300 174 6 77 69 79 62 139 98 -301 174 6 81 70 81 60 152 107 -92 175 1 96 80 86 40 65 61 -93 175 1 101 82 88 57 102 92 -94 175 1 103 87 94 60 119 111 -95 175 1 109 95 101 60 102 91 -96 175 1 115 105 119 72 121 105 -97 175 1 139 136 164 94 166 133 -98 175 1 147 155 191 104 207 163 -99 175 1 143 146 179 100 196 163 -100 175 1 110 100 112 75 105 79 -101 175 1 97 84 93 62 90 70 -102 175 1 100 83 91 58 94 77 -103 175 1 104 88 98 58 102 90 -104 175 1 113 98 111 59 109 101 -105 175 1 115 101 113 58 110 102 -264 175 5 76 58 62 62 95 60 -265 175 5 74 59 64 66 114 69 -266 175 5 79 65 74 67 117 76 -267 175 5 79 64 69 58 103 68 -268 175 5 76 60 64 56 84 52 -269 175 5 70 53 51 58 87 51 -270 175 5 69 55 45 60 73 42 -271 175 5 68 55 46 62 69 41 -272 175 5 73 56 57 61 91 53 -273 175 5 74 57 64 58 101 62 -274 175 5 78 59 65 61 114 74 -293 175 6 76 60 66 63 117 74 -294 175 6 76 60 64 63 115 73 -295 175 6 78 64 72 65 134 87 -296 175 6 78 64 73 64 134 88 -297 175 6 77 62 67 61 121 78 -298 175 6 78 61 67 55 114 77 -299 175 6 79 65 72 56 113 80 -300 175 6 80 69 81 60 138 101 -301 175 6 81 69 83 61 148 107 -91 176 1 94 73 80 46 67 60 -92 176 1 92 69 73 30 38 37 -93 176 1 91 74 73 39 51 45 -94 176 1 101 84 85 48 61 50 -95 176 1 103 88 96 58 98 82 -96 176 1 108 90 101 56 102 100 -97 176 1 112 98 108 62 114 100 -98 176 1 120 116 129 80 151 122 -99 176 1 128 120 141 82 154 117 -100 176 1 102 85 99 62 105 77 -101 176 1 100 90 95 61 92 75 -102 176 1 104 90 100 61 95 82 -103 176 1 89 72 73 42 59 54 -104 176 1 95 77 78 44 64 62 -105 176 1 115 102 109 59 108 104 -264 176 5 74 61 64 65 108 67 -265 176 5 73 58 61 64 88 53 -266 176 5 81 65 76 63 123 78 -267 176 5 81 64 71 57 90 64 -268 176 5 74 58 57 57 83 51 -269 176 5 70 56 50 60 71 42 -270 176 5 69 55 48 63 67 37 -271 176 5 71 54 47 59 71 45 -272 176 5 75 57 61 57 89 53 -273 176 5 77 58 63 62 107 65 -274 176 5 76 62 68 62 114 72 -293 176 6 76 59 63 64 124 80 -294 176 6 77 59 64 67 130 83 -295 176 6 80 66 73 69 143 93 -296 176 6 76 66 74 67 137 88 -297 176 6 78 63 69 65 123 78 -298 176 6 79 64 69 60 116 77 -299 176 6 78 65 73 59 122 85 -300 176 6 80 68 80 60 139 99 -301 176 6 84 71 84 61 143 103 -91 177 1 104 82 91 45 61 54 -92 177 1 93 68 67 33 37 37 -93 177 1 94 75 76 36 42 36 -94 177 1 102 83 84 45 69 60 -95 177 1 102 82 92 50 80 71 -96 177 1 107 89 99 59 98 86 -97 177 1 104 89 100 64 89 77 -98 177 1 110 97 106 71 110 85 -99 177 1 101 88 100 60 99 79 -100 177 1 96 82 90 52 72 63 -101 177 1 107 89 100 53 85 82 -102 177 1 105 87 95 51 82 73 -103 177 1 105 87 95 51 82 73 -264 177 5 74 58 59 58 97 58 -265 177 5 72 56 58 59 97 56 -266 177 5 79 63 71 61 113 75 -267 177 5 83 67 69 58 91 66 -268 177 5 81 62 67 59 94 63 -269 177 5 72 57 60 59 92 57 -270 177 5 72 56 57 59 81 47 -271 177 5 71 54 48 59 77 44 -272 177 5 72 57 59 61 86 50 -273 177 5 74 56 61 61 107 63 -274 177 5 75 59 65 59 106 70 -293 177 6 77 59 62 64 113 73 -294 177 6 76 64 68 67 123 78 -295 177 6 80 67 71 68 125 81 -296 177 6 79 66 77 67 133 89 -297 177 6 78 63 69 65 123 78 -298 177 6 78 62 65 63 124 81 -299 177 6 76 60 64 60 119 80 -300 177 6 81 66 78 61 138 96 -301 177 6 84 74 88 62 148 105 -92 178 1 102 86 90 48 65 59 -93 178 1 99 76 80 39 54 49 -94 178 1 96 72 74 36 44 42 -95 178 1 92 73 74 43 49 44 -96 178 1 100 86 94 58 91 75 -97 178 1 105 85 94 58 89 76 -98 178 1 101 91 99 67 102 87 -99 178 1 99 82 81 55 73 61 -100 178 1 136 134 152 75 119 113 -101 178 1 138 124 142 67 106 99 -102 178 1 108 94 101 59 118 103 -264 178 5 74 58 62 57 99 62 -265 178 5 74 57 62 59 96 60 -266 178 5 76 61 63 58 82 53 -267 178 5 80 65 66 59 97 62 -268 178 5 77 58 64 61 90 59 -269 178 5 73 60 64 62 100 60 -270 178 5 72 58 57 55 81 49 -271 178 5 69 51 45 57 66 38 -272 178 5 69 55 49 62 78 49 -273 178 5 71 55 54 60 88 53 -274 178 5 76 59 62 63 93 55 -293 178 6 76 65 69 57 111 75 -294 178 6 80 66 73 59 122 81 -295 178 6 83 68 78 59 126 86 -296 178 6 82 69 79 59 128 88 -297 178 6 78 63 69 64 129 86 -298 178 6 78 61 65 61 122 83 -299 178 6 80 69 79 61 139 97 -300 178 6 80 69 79 61 139 97 -301 178 6 81 72 85 63 138 102 -92 179 1 111 91 102 56 91 79 -93 179 1 107 87 96 52 82 74 -94 179 1 102 83 90 45 65 59 -95 179 1 99 79 83 45 59 51 -96 179 1 99 85 85 62 75 66 -97 179 1 101 84 92 65 92 76 -98 179 1 105 93 97 58 85 72 -99 179 1 128 119 129 68 108 98 -100 179 1 163 168 194 89 145 144 -93 180 1 109 93 104 57 91 80 -94 180 1 108 90 100 58 94 81 -95 180 1 104 90 97 63 88 75 -96 180 1 101 84 86 63 80 71 -97 180 1 102 84 92 68 90 73 -98 180 1 106 95 101 55 84 76 -93 181 1 114 95 110 50 98 87 -94 181 1 110 91 99 60 98 84 -95 181 1 100 84 92 69 94 75 -96 181 1 104 89 97 66 89 79 -94 182 1 99 81 85 70 93 76 -192 188 6 68 48 36 15 15 13 -193 188 6 66 46 37 16 15 11 -194 188 6 66 46 35 14 13 13 -195 188 6 66 47 36 15 14 12 -196 188 6 66 46 36 14 13 11 -197 188 6 68 45 36 15 14 14 -198 188 6 64 45 35 14 12 13 -199 188 6 66 47 35 13 12 10 -200 188 6 65 47 35 13 13 11 -201 188 6 66 45 35 15 13 13 -202 188 6 64 44 34 15 12 12 -203 188 6 66 46 34 15 14 11 -204 188 6 65 46 35 15 13 13 -192 189 6 66 46 36 15 14 12 -193 189 6 68 46 36 15 14 11 -194 189 6 67 45 36 15 15 13 -195 189 6 65 47 36 15 14 11 -196 189 6 67 44 37 15 15 12 -197 189 6 67 47 37 15 13 12 -198 189 6 67 45 37 15 13 13 -199 189 6 64 46 33 15 13 12 -200 189 6 65 46 35 15 14 11 -201 189 6 66 44 36 15 14 12 -202 189 6 66 44 34 15 13 9 -203 189 6 66 46 36 15 12 10 -204 189 6 66 46 36 15 13 13 -193 190 6 69 46 36 14 13 12 -194 190 6 67 46 34 16 14 12 -195 190 6 67 46 36 15 14 14 -196 190 6 65 45 34 15 14 11 -197 190 6 66 48 39 16 14 10 -198 190 6 67 47 36 15 15 11 -199 190 6 64 45 35 15 14 14 -200 190 6 65 44 34 15 14 11 -201 190 6 66 45 36 15 13 13 -202 190 6 66 46 35 15 12 10 -203 190 6 64 46 36 14 13 11 -204 190 6 66 46 33 15 14 12 -193 191 6 68 47 36 15 15 11 -194 191 6 67 47 35 15 14 13 -195 191 6 68 46 37 14 13 11 -196 191 6 65 46 33 14 15 13 -197 191 6 66 46 39 15 14 12 -198 191 6 66 47 34 16 14 11 -199 191 6 66 45 36 15 13 12 -200 191 6 66 45 35 14 13 13 -201 191 6 66 46 35 14 12 11 -202 191 6 65 46 37 14 13 12 -203 191 6 65 46 34 15 15 11 -204 191 6 66 46 31 15 14 11 -193 192 6 66 47 36 15 14 12 -194 192 6 68 46 36 14 14 12 -195 192 6 68 46 37 14 13 11 -196 192 6 66 46 36 15 15 14 -197 192 6 68 48 39 15 13 12 -198 192 6 66 45 34 15 14 11 -199 192 6 67 46 34 15 13 12 -200 192 6 66 45 36 13 14 13 -201 192 6 68 45 35 14 12 10 -202 192 6 66 45 37 15 13 12 -203 192 6 66 45 33 15 14 12 -204 192 6 67 45 33 15 13 13 -194 193 6 66 46 35 15 14 13 -195 193 6 65 46 37 16 14 13 -196 193 6 67 47 37 14 15 11 -197 193 6 67 45 36 14 13 11 -198 193 6 64 47 33 15 14 14 -199 193 6 64 47 33 15 14 14 -200 193 6 67 44 37 14 15 11 -201 193 6 66 45 35 15 12 12 -202 193 6 66 46 35 14 12 13 -203 193 6 65 45 35 14 13 13 -204 193 6 66 45 35 15 14 12 -194 194 6 67 48 34 14 14 11 -195 194 6 67 45 36 16 13 11 -196 194 6 66 45 34 15 16 12 -197 194 6 67 47 37 15 13 12 -198 194 6 65 45 35 15 14 13 -199 194 6 65 45 34 15 14 11 -200 194 6 66 46 35 15 13 13 -201 194 6 67 44 36 15 14 14 -202 194 6 67 46 34 14 13 11 -203 194 6 66 46 35 15 13 12 -204 194 6 65 45 34 15 14 11 -194 195 6 67 46 35 15 15 12 -195 195 6 66 46 38 15 13 10 -196 195 6 68 47 34 15 15 12 -197 195 6 66 46 36 14 13 12 -198 195 6 65 46 33 15 15 10 -199 195 6 66 45 36 15 12 11 -200 195 6 66 45 33 14 14 15 -201 195 6 65 45 36 14 13 12 -202 195 6 66 45 35 15 14 10 -203 195 6 65 44 35 15 14 12 -204 195 6 66 47 36 14 14 13 -195 196 6 65 44 35 16 15 13 -196 196 6 67 45 37 15 14 13 -197 196 6 67 46 35 15 14 12 -198 196 6 66 46 34 15 15 11 -199 196 6 65 47 36 15 14 12 -200 196 6 67 45 35 15 14 13 -201 196 6 65 45 36 14 13 12 -202 196 6 64 45 35 15 15 11 -203 196 6 66 46 34 15 15 13 -294 227 4 86 73 78 55 73 53 -295 227 4 83 69 71 64 83 60 -296 227 4 86 71 70 69 85 62 -297 227 4 85 70 70 66 90 67 -298 227 4 89 74 77 64 80 60 -289 228 4 80 69 74 70 107 63 -290 228 4 80 71 79 64 107 73 -291 228 4 88 74 84 61 102 78 -292 228 4 95 82 93 56 90 70 -293 228 4 89 76 85 64 89 62 -294 228 4 83 70 71 73 90 61 -295 228 4 83 70 71 73 90 61 -296 228 4 86 71 73 73 90 62 -297 228 4 88 73 78 73 99 72 -298 228 4 92 78 83 78 102 75 -290 229 4 84 71 76 59 76 54 -291 229 4 87 75 84 62 102 69 -292 229 4 94 82 92 57 98 82 -293 229 4 92 82 93 64 102 76 -294 229 4 90 80 88 68 98 69 -295 229 4 93 81 88 68 98 72 -296 229 4 93 79 88 72 107 77 -297 229 4 98 84 96 66 110 84 -298 229 4 94 81 89 58 98 79 -290 230 4 79 63 66 62 83 60 -291 230 4 76 63 66 74 101 61 -292 230 4 89 74 81 61 98 73 -293 230 4 82 69 74 57 84 65 -294 230 4 85 70 75 52 77 58 -295 230 4 91 71 71 48 69 55 -296 230 4 86 68 69 53 81 58 -297 230 4 96 82 93 61 102 78 -298 230 4 100 90 102 62 95 80 -290 231 4 86 71 80 61 115 79 -291 231 4 75 60 60 74 89 53 -292 231 4 83 67 67 65 88 56 -133 244 4 69 56 44 71 72 38 -134 244 4 68 54 43 73 71 38 -135 244 4 73 59 53 80 82 45 -136 244 4 73 59 56 84 85 45 -137 244 4 69 61 50 83 92 48 -138 244 4 87 76 77 91 109 70 -139 244 4 93 82 79 113 113 72 -140 244 4 75 59 60 84 90 47 -133 245 4 73 60 53 77 93 51 -134 245 4 72 59 52 84 90 47 -135 245 4 76 66 58 87 104 58 -136 245 4 76 66 67 88 109 63 -137 245 4 80 67 67 82 116 67 -138 245 4 77 68 63 90 114 66 -139 245 4 88 81 73 107 115 79 -140 245 4 75 64 56 94 92 49 -133 246 4 73 60 53 77 93 51 -134 246 4 77 64 60 85 106 60 -135 246 4 77 68 66 85 112 65 -136 246 4 79 68 70 87 119 65 -137 246 4 81 72 74 85 128 77 -138 246 4 77 65 65 86 104 55 -139 246 4 81 68 64 81 83 51 -140 246 4 81 66 61 100 75 43 -134 247 4 80 71 73 83 123 73 -135 247 4 78 67 67 78 112 64 -136 247 4 77 64 62 86 108 59 -137 247 4 79 70 70 89 122 70 -138 247 4 80 65 66 80 114 68 -139 247 4 79 64 61 79 81 50 -140 247 4 75 64 59 90 79 43 -141 247 4 70 58 47 101 78 37 -250 247 4 69 55 48 63 68 38 -251 247 4 77 67 71 70 98 61 -134 248 4 79 68 68 79 118 70 -135 248 4 78 62 66 75 106 64 -136 248 4 86 74 78 74 110 72 -137 248 4 87 74 79 69 110 71 -138 248 4 82 71 71 76 106 69 -139 248 4 81 70 67 92 91 50 -140 248 4 81 72 67 91 100 56 -141 248 4 80 67 62 87 89 55 -250 248 4 80 63 60 64 81 52 -251 248 4 87 76 78 72 105 76 -252 248 4 85 76 75 89 109 77 -253 248 4 88 78 79 83 116 78 -254 248 4 89 80 89 73 103 77 -134 249 4 88 76 79 66 110 74 -135 249 4 84 66 74 64 96 68 -136 249 4 83 75 75 78 104 72 -137 249 4 86 74 78 77 90 63 -138 249 4 81 73 72 69 98 62 -139 249 4 80 70 67 91 108 68 -140 249 4 90 73 75 88 105 67 -141 249 4 86 69 65 77 84 50 -251 249 4 84 73 71 95 93 61 -252 249 4 76 61 49 107 84 41 -253 249 4 85 75 74 97 125 74 -254 249 4 83 78 85 87 133 83 -251 250 4 90 81 88 85 126 85 -252 250 4 82 70 65 90 77 47 -253 250 4 90 78 79 84 108 71 -254 250 4 85 79 84 90 134 86 -252 251 4 86 80 82 86 116 82 -253 251 4 84 78 77 98 112 73 -254 251 4 83 75 76 111 121 69 -378 253 6 74 59 55 60 100 61 -377 254 6 75 61 62 68 108 61 -378 254 6 74 59 57 49 71 48 -379 254 6 69 54 45 14 11 12 -376 255 6 70 55 49 66 78 44 -377 255 6 75 61 62 68 108 61 -378 255 6 74 60 57 42 82 53 -379 255 6 72 54 46 16 18 16 -376 256 6 76 61 59 68 106 62 -377 256 6 74 59 52 30 53 36 -378 256 6 69 54 44 14 6 7 -376 257 6 76 61 59 65 93 56 -377 257 6 73 57 52 23 44 30 -132 274 4 72 58 59 62 94 59 -132 275 4 74 58 58 64 97 58 -133 275 4 74 63 65 72 114 64 -134 275 4 74 63 65 72 114 64 -135 275 4 75 58 60 59 82 52 -136 275 4 73 55 51 54 49 31 -137 275 4 64 43 34 23 16 14 -132 276 4 72 57 54 60 97 56 -133 276 4 75 65 68 77 123 70 -134 276 4 73 53 55 49 61 37 -135 276 4 61 40 30 12 10 11 -136 276 4 64 42 34 19 24 20 -137 276 4 68 47 42 42 63 37 -132 277 4 71 55 51 61 91 52 -133 277 4 74 63 61 80 114 63 -134 277 4 74 59 55 67 74 41 -135 277 4 69 50 40 40 35 24 -136 277 4 64 44 35 18 41 30 -137 277 4 71 54 52 53 96 52 -132 278 4 71 56 50 65 75 44 -133 278 4 73 60 58 75 99 54 -134 278 4 79 64 64 79 122 69 -135 278 4 77 63 59 75 109 61 -136 278 4 70 54 46 43 57 37 -137 278 4 76 62 62 69 95 55 -132 279 4 73 58 54 63 85 52 -133 279 4 73 57 56 66 94 55 -134 279 4 76 61 61 71 104 62 -135 279 4 77 63 67 73 109 62 -136 279 4 76 62 60 68 106 63 -137 279 4 75 63 59 82 116 66 -360 290 5 68 48 46 67 109 60 -361 290 5 73 56 59 64 129 79 -362 290 5 78 60 70 66 130 82 -363 290 5 78 62 65 64 120 71 -364 290 5 76 60 61 66 110 68 -365 290 5 75 57 61 64 116 70 -366 290 5 76 63 67 63 124 75 -367 290 5 78 60 63 59 118 74 -368 290 5 76 59 68 62 125 77 -369 290 5 76 60 64 63 117 73 -370 290 5 75 60 63 66 121 75 -371 290 5 72 58 57 68 105 64 -360 291 5 85 72 82 71 127 86 -361 291 5 88 75 84 69 130 87 -362 291 5 78 62 72 65 137 86 -363 291 5 80 64 68 64 124 78 -364 291 5 72 57 58 67 110 65 -365 291 5 77 60 68 63 124 78 -366 291 5 77 60 65 60 125 80 -367 291 5 78 63 66 61 123 74 -368 291 5 75 60 64 62 127 77 -369 291 5 75 62 67 61 126 79 -370 291 5 74 60 61 68 117 70 -371 291 5 72 56 50 73 96 52 -361 292 5 80 62 70 64 127 82 -362 292 5 77 62 66 64 119 75 -363 292 5 78 61 67 63 121 75 -364 292 5 74 59 65 63 117 73 -365 292 5 78 62 69 63 123 77 -366 292 5 76 60 65 62 122 76 -367 292 5 78 62 70 63 132 79 -368 292 5 75 60 69 64 127 79 -369 292 5 77 63 71 61 130 85 -370 292 5 74 59 56 64 102 61 -371 292 5 70 53 47 66 90 45 -361 293 5 73 58 62 64 119 82 -362 293 5 74 60 64 65 119 74 -363 293 5 77 59 65 63 124 75 -364 293 5 79 62 66 63 123 77 -365 293 5 77 60 68 64 125 80 -366 293 5 77 62 70 63 130 80 -367 293 5 80 62 75 63 133 85 -368 293 5 77 61 70 63 128 82 -369 293 5 74 55 54 59 90 54 -370 293 5 73 57 52 60 89 51 -371 293 5 76 57 62 63 120 73 -361 294 5 69 54 53 61 96 62 -362 294 5 76 60 63 67 114 69 -363 294 5 76 61 66 63 123 74 -364 294 5 79 62 70 65 131 81 -365 294 5 77 60 66 63 122 76 -366 294 5 75 61 66 62 124 76 -367 294 5 77 61 67 61 120 70 -368 294 5 77 59 66 63 116 71 -369 294 5 73 56 53 63 92 51 -370 294 5 76 58 60 63 112 67 -371 294 5 79 60 68 63 129 80 -361 295 5 73 58 59 61 85 51 -362 295 5 74 58 58 70 103 58 -363 295 5 77 61 63 65 117 72 -364 295 5 79 63 72 64 132 83 -365 295 5 76 59 63 61 122 73 -366 295 5 73 58 60 60 109 65 -367 295 5 76 59 55 61 96 56 -368 295 5 76 56 58 60 98 60 -369 295 5 71 57 54 67 92 52 -370 295 5 74 56 60 64 108 63 -371 295 5 77 57 61 60 108 66 -361 296 5 76 58 63 69 104 60 -362 296 5 79 63 67 61 127 80 -363 296 5 75 58 67 59 122 78 -364 296 5 75 56 59 59 105 62 -365 296 5 73 57 55 61 88 51 -366 296 5 71 58 55 68 99 56 -367 296 5 74 56 53 61 87 51 -368 296 5 71 56 55 66 90 53 -369 296 5 73 55 54 64 92 53 -370 296 5 72 54 50 63 84 51 -371 296 5 70 57 49 68 89 50 -361 297 5 74 57 64 67 113 67 -362 297 5 76 63 68 61 126 82 -363 297 5 76 59 65 58 115 71 -364 297 5 74 59 59 60 99 61 -365 297 5 73 59 54 67 99 55 -366 297 5 72 56 54 72 107 57 -367 297 5 73 59 55 69 100 55 -368 297 5 73 59 54 67 97 56 -369 297 5 73 58 53 69 93 54 -370 297 5 73 56 52 72 85 48 -371 297 5 72 58 54 70 94 52 -361 298 5 78 61 68 60 116 74 -362 298 5 77 60 61 60 111 69 -363 298 5 74 59 62 64 110 64 -364 298 5 76 60 65 63 110 68 -365 298 5 71 58 54 65 106 62 -366 298 5 71 54 54 65 95 52 -367 298 5 71 55 51 71 101 55 -368 298 5 73 57 51 66 96 55 -369 298 5 72 57 53 67 98 57 -370 298 5 75 59 59 68 105 60 -371 298 5 76 60 64 63 115 69 -362 299 5 75 58 64 60 112 72 -363 299 5 75 57 59 62 112 67 -364 299 5 72 55 57 65 101 60 -365 299 5 71 56 51 66 91 52 -366 299 5 72 55 52 65 94 55 -367 299 5 71 57 50 65 95 53 -368 299 5 71 57 50 65 95 53 -369 299 5 72 55 56 66 102 59 -370 299 5 76 60 63 60 124 77 -371 299 5 81 65 70 53 130 85 -362 300 5 74 58 64 59 115 74 -363 300 5 74 57 59 60 113 70 -364 300 5 74 59 58 64 112 66 -365 300 5 74 59 61 65 106 63 -366 300 5 76 58 56 65 105 61 -367 300 5 72 56 54 66 103 60 -368 300 5 75 57 58 61 111 65 -369 300 5 76 59 65 55 117 79 -370 300 5 84 72 81 56 130 94 -371 300 5 85 72 82 59 128 96 -362 301 5 74 57 65 60 118 74 -363 301 5 73 57 59 63 107 64 -364 301 5 76 58 60 64 118 71 -365 301 5 77 60 65 66 123 75 -366 301 5 73 56 57 62 106 63 -367 301 5 75 59 59 62 111 67 -368 301 5 71 56 57 58 104 63 -369 301 5 81 64 69 56 106 77 -370 301 5 89 75 84 57 118 95 -371 301 5 77 66 68 59 112 73 -362 302 5 75 58 62 62 116 70 -363 302 5 75 58 56 68 107 61 -364 302 5 76 60 65 67 118 72 -365 302 5 76 59 65 66 121 76 -366 302 5 73 56 57 62 106 63 -367 302 5 70 56 58 59 93 54 -368 302 5 75 63 62 57 102 69 -369 302 5 86 76 86 59 117 94 -370 302 5 83 70 80 59 113 84 -371 302 5 73 57 58 59 100 58 -363 303 5 72 56 52 68 99 54 -364 303 5 74 58 64 68 115 70 -365 303 5 74 61 59 66 109 66 -366 303 5 71 58 60 60 97 59 -367 303 5 69 59 59 57 92 53 -368 303 5 83 71 79 59 115 83 -369 303 5 87 74 84 61 124 94 -370 303 5 78 59 65 58 106 64 -371 303 5 73 54 56 57 92 58 -345 307 7 72 59 50 66 73 41 -346 307 7 83 71 70 70 88 58 -347 307 7 112 103 117 65 132 115 -348 307 7 125 118 135 65 138 133 -349 307 7 125 112 129 64 126 118 -350 307 7 121 108 122 59 124 117 -351 307 7 125 113 126 62 131 129 -345 308 7 72 60 47 69 82 46 -346 308 7 79 66 61 77 85 52 -347 308 7 116 105 115 61 112 102 -348 308 7 123 113 126 65 127 125 -349 308 7 125 113 126 63 116 114 -350 308 7 118 108 121 63 107 103 -351 308 7 132 125 148 71 130 124 -198 309 5 69 53 54 62 82 49 -199 309 5 72 54 57 56 94 58 -200 309 5 72 56 57 65 98 60 -201 309 5 74 59 60 70 107 65 -202 309 5 75 59 60 68 116 70 -203 309 5 71 59 54 69 112 68 -204 309 5 74 58 63 62 101 63 -205 309 5 77 59 68 63 111 68 -206 309 5 76 56 62 57 117 71 -207 309 5 73 58 59 61 118 71 -208 309 5 75 61 67 62 127 82 -209 309 5 80 65 70 63 122 84 -345 309 7 74 58 52 72 83 47 -346 309 7 92 79 84 64 95 72 -347 309 7 124 108 124 60 124 117 -348 309 7 138 123 135 64 142 137 -349 309 7 138 123 135 64 142 137 -350 309 7 146 135 148 71 145 139 -351 309 7 143 132 150 73 142 145 -198 310 5 68 51 50 60 73 42 -199 310 5 69 53 50 63 74 44 -200 310 5 71 56 53 66 86 49 -201 310 5 74 58 57 71 104 62 -202 310 5 74 57 57 69 106 65 -203 310 5 71 57 53 66 96 55 -204 310 5 75 60 68 64 112 71 -205 310 5 77 63 68 63 120 75 -206 310 5 71 53 49 53 80 48 -207 310 5 71 54 54 61 94 57 -208 310 5 74 58 62 65 110 69 -209 310 5 78 60 66 64 109 70 -345 310 7 72 56 47 70 74 41 -346 310 7 79 68 68 73 96 58 -347 310 7 113 101 113 60 117 113 -348 310 7 149 137 151 70 165 159 -349 310 7 170 157 176 80 182 183 -350 310 7 144 132 151 72 150 162 -351 310 7 147 138 164 79 145 145 -199 311 5 71 55 56 63 85 49 -200 311 5 73 56 56 65 85 51 -201 311 5 74 58 58 70 100 60 -202 311 5 73 57 56 68 100 58 -203 311 5 73 59 59 71 102 56 -204 311 5 77 62 68 68 121 75 -205 311 5 75 55 57 53 98 62 -206 311 5 69 52 44 52 60 36 -207 311 5 71 53 49 61 76 43 -208 311 5 74 61 64 68 120 72 -209 311 5 76 62 65 66 109 67 -345 311 7 68 52 43 62 59 35 -346 311 7 72 58 53 64 75 43 -347 311 7 97 87 102 62 111 89 -348 311 7 132 125 148 71 151 143 -349 311 7 151 140 166 77 161 161 -350 311 7 139 132 155 75 139 138 -351 311 7 153 143 170 82 152 150 -199 312 5 71 56 56 58 91 54 -200 312 5 71 56 53 60 85 54 -201 312 5 71 55 53 64 92 53 -202 312 5 73 58 58 70 98 55 -203 312 5 73 57 56 70 109 62 -204 312 5 74 56 59 57 108 69 -205 312 5 71 53 51 50 72 44 -206 312 5 70 52 46 55 63 38 -207 312 5 71 53 47 58 73 43 -208 312 5 75 59 61 65 117 69 -209 312 5 75 62 67 65 125 78 -345 312 7 69 50 43 58 48 30 -346 312 7 72 55 45 64 56 32 -347 312 7 80 64 70 65 94 54 -348 312 7 102 95 111 69 122 103 -349 312 7 123 114 131 69 130 123 -350 312 7 129 117 130 63 119 113 -351 312 7 128 115 130 64 126 121 -199 313 5 71 57 51 64 79 47 -200 313 5 71 58 55 65 87 51 -201 313 5 75 60 60 68 99 58 -202 313 5 71 57 55 66 94 54 -203 313 5 70 56 56 64 99 58 -204 313 5 71 51 49 49 73 47 -205 313 5 70 52 48 58 65 37 -206 313 5 70 53 48 58 70 40 -207 313 5 67 52 46 54 62 38 -208 313 5 72 56 53 61 95 55 -209 313 5 74 59 60 66 119 71 -345 313 7 66 49 42 57 48 27 -346 313 7 72 55 47 69 72 41 -347 313 7 66 54 45 66 64 32 -348 313 7 82 71 79 71 89 59 -349 313 7 117 106 114 64 111 108 -350 313 7 117 104 109 60 104 100 -351 313 7 104 89 95 58 84 70 -199 314 5 73 58 56 64 86 51 -200 314 5 74 59 59 61 96 61 -201 314 5 75 59 63 61 105 65 -202 314 5 72 56 53 54 82 48 -203 314 5 68 52 49 52 60 37 -204 314 5 69 54 46 59 64 37 -205 314 5 67 51 46 58 66 36 -206 314 5 69 51 44 58 62 35 -207 314 5 69 53 46 61 65 37 -208 314 5 72 57 54 62 94 53 -209 314 5 71 54 51 54 92 56 -199 315 5 72 59 59 62 98 59 -200 315 5 77 60 65 60 112 70 -201 315 5 77 59 69 58 111 69 -202 315 5 74 57 59 54 85 51 -203 315 5 73 54 54 56 80 48 -204 315 5 68 56 47 61 70 40 -205 315 5 67 53 44 62 64 35 -206 315 5 70 51 45 62 70 37 -207 315 5 70 50 45 62 69 38 -208 315 5 68 56 50 64 74 42 -209 315 5 71 53 49 60 74 44 -199 316 5 76 63 70 67 116 69 -200 316 5 80 63 76 61 126 76 -201 316 5 77 59 69 58 111 69 -202 316 5 77 61 70 60 112 70 -203 316 5 74 57 61 61 102 61 -204 316 5 69 54 48 62 79 44 -205 316 5 68 51 42 59 62 34 -206 316 5 67 52 43 61 60 33 -207 316 5 69 53 43 65 65 35 -208 316 5 69 52 47 63 66 37 -209 316 5 70 53 47 64 71 40 -199 317 5 79 64 75 68 130 83 -200 317 5 77 63 70 60 121 74 -201 317 5 77 62 72 61 118 73 -202 317 5 78 62 68 64 120 74 -203 317 5 73 58 62 63 105 63 -204 317 5 72 54 52 61 79 48 -205 317 5 69 50 43 59 62 35 -206 317 5 66 52 43 63 63 36 -207 317 5 67 52 43 65 68 38 -208 317 5 70 52 43 67 69 38 -209 317 5 69 54 44 67 71 38 -240 317 3 75 67 72 89 101 64 -241 317 3 77 70 78 89 109 67 -242 317 3 88 84 101 85 136 102 -243 317 3 90 81 89 94 133 105 -244 317 3 86 80 90 94 134 98 -245 317 3 78 74 74 106 118 77 -246 317 3 91 84 98 93 135 101 -247 317 3 86 80 89 89 120 85 -248 317 3 80 74 75 91 109 73 -274 317 3 73 63 56 105 100 51 -275 317 3 74 63 51 113 98 49 -276 317 3 74 63 50 117 100 49 -277 317 3 74 66 54 116 102 54 -278 317 3 75 66 53 110 103 51 -279 317 3 72 63 56 107 96 46 -280 317 3 74 64 56 110 98 49 -281 317 3 78 71 65 99 121 66 -282 317 3 80 71 66 99 122 69 -283 317 3 80 68 69 94 127 76 -284 317 3 80 73 69 103 123 68 -285 317 3 81 72 69 94 126 73 -286 317 3 80 75 77 84 131 79 -287 317 3 81 68 70 86 113 71 -288 317 3 76 65 63 98 108 70 -289 317 3 88 75 83 94 138 90 -199 318 5 75 58 65 60 119 72 -200 318 5 73 59 61 60 107 69 -201 318 5 74 61 66 64 115 70 -202 318 5 75 58 62 59 107 64 -203 318 5 75 61 63 62 104 62 -204 318 5 75 58 58 60 96 57 -205 318 5 73 53 52 59 79 46 -206 318 5 71 54 52 65 77 43 -207 318 5 70 54 52 67 80 47 -208 318 5 68 52 42 71 75 44 -209 318 5 66 54 44 68 73 37 -240 318 3 83 77 87 90 121 82 -241 318 3 81 73 75 92 117 75 -242 318 3 79 72 73 96 108 67 -243 318 3 77 71 74 100 109 67 -244 318 3 78 71 79 96 128 85 -245 318 3 81 75 83 94 120 77 -246 318 3 83 77 80 94 115 75 -247 318 3 95 93 108 81 130 106 -248 318 3 85 80 84 92 124 91 -249 318 3 72 60 52 102 96 47 -274 318 3 72 63 53 110 99 50 -275 318 3 73 63 52 112 98 48 -276 318 3 74 63 54 114 103 53 -277 318 3 76 66 56 116 107 57 -278 318 3 75 67 55 109 108 59 -279 318 3 72 62 53 106 98 53 -280 318 3 74 64 55 115 96 45 -281 318 3 74 69 61 114 111 57 -282 318 3 77 68 57 110 107 59 -283 318 3 78 69 66 102 123 66 -284 318 3 78 71 64 98 120 67 -285 318 3 78 68 68 94 122 73 -286 318 3 79 70 64 98 118 65 -287 318 3 74 62 55 82 101 55 -288 318 3 105 96 110 79 139 116 -289 318 3 88 75 83 94 138 90 -240 319 3 91 89 103 82 137 108 -241 319 3 93 89 106 79 136 106 -242 319 3 91 84 100 85 128 98 -243 319 3 88 84 105 85 133 102 -244 319 3 90 86 111 81 147 110 -245 319 3 88 83 92 88 133 94 -246 319 3 94 91 105 83 136 109 -247 319 3 83 77 80 96 120 88 -248 319 3 71 62 51 101 103 61 -249 319 3 76 64 56 97 102 58 -275 319 3 73 61 50 108 100 52 -276 319 3 74 64 58 106 108 56 -277 319 3 76 64 55 111 112 55 -278 319 3 74 61 53 95 100 53 -279 319 3 70 57 47 80 84 47 -280 319 3 72 64 52 90 90 47 -281 319 3 74 66 58 104 106 53 -282 319 3 75 63 51 101 99 53 -283 319 3 77 67 58 110 105 51 -284 319 3 73 66 53 104 105 54 -285 319 3 73 63 58 107 96 49 -286 319 3 75 65 49 115 95 45 -287 319 3 69 57 39 101 83 34 -288 319 3 127 118 141 81 164 136 -289 319 3 109 99 113 89 152 118 -240 320 3 78 69 65 95 108 67 -241 320 3 79 75 78 90 116 81 -242 320 3 85 77 88 91 123 90 -243 320 3 81 74 81 97 122 86 -244 320 3 74 66 64 108 114 76 -245 320 3 88 85 96 89 137 105 -246 320 3 77 68 65 103 109 74 -247 320 3 75 61 54 104 95 48 -248 320 3 74 64 58 95 94 49 -249 320 3 75 63 57 100 92 51 -275 320 3 72 60 51 105 91 46 -276 320 3 74 66 60 96 113 61 -277 320 3 76 65 60 96 114 61 -278 320 3 74 59 57 76 98 54 -279 320 3 72 59 55 70 80 47 -280 320 3 74 64 55 79 92 56 -281 320 3 76 63 55 95 95 52 -282 320 3 74 64 55 103 108 60 -283 320 3 75 63 54 104 101 52 -284 320 3 74 67 51 112 107 56 -285 320 3 74 63 53 112 103 51 -286 320 3 71 63 48 116 99 49 -287 320 3 70 57 36 118 85 36 -288 320 3 107 98 114 94 145 117 -289 320 3 137 127 149 93 185 154 -348 320 7 116 111 127 70 125 110 -349 320 7 125 118 135 70 120 113 -350 320 7 137 132 154 74 137 131 -240 321 3 90 88 96 79 112 83 -241 321 3 86 77 83 87 104 69 -242 321 3 82 71 73 95 105 59 -243 321 3 75 68 65 104 101 52 -244 321 3 76 65 59 111 87 41 -245 321 3 73 62 55 114 104 59 -246 321 3 74 67 59 103 89 42 -247 321 3 78 69 65 89 96 50 -248 321 3 77 70 68 91 107 68 -249 321 3 77 69 62 99 95 58 -275 321 3 75 65 60 91 116 63 -276 321 3 75 65 60 91 116 63 -277 321 3 77 66 65 83 120 66 -278 321 3 77 62 61 81 103 59 -279 321 3 75 67 63 92 106 60 -280 321 3 77 69 68 91 116 66 -281 321 3 77 63 58 92 96 54 -282 321 3 78 69 60 105 109 56 -283 321 3 75 64 53 105 110 56 -284 321 3 76 67 52 113 110 57 -285 321 3 75 66 56 112 110 55 -286 321 3 77 68 58 114 107 57 -287 321 3 75 68 53 118 103 50 -288 321 3 81 72 69 105 111 65 -289 321 3 124 116 131 97 177 144 -348 321 7 130 119 138 67 127 122 -349 321 7 132 116 128 65 119 117 -350 321 7 130 120 137 63 122 119 -240 322 3 82 77 78 88 117 91 -241 322 3 86 75 83 89 120 92 -242 322 3 89 78 89 88 124 94 -243 322 3 82 78 80 88 113 80 -244 322 3 73 61 54 85 86 49 -245 322 3 79 69 61 107 89 46 -246 322 3 81 76 82 92 113 76 -247 322 3 90 87 102 80 129 96 -248 322 3 89 83 94 78 123 95 -249 322 3 81 74 80 89 109 77 -275 322 3 72 63 55 89 103 56 -276 322 3 65 53 44 94 91 45 -277 322 3 86 74 74 97 113 68 -278 322 3 109 105 115 105 131 95 -279 322 3 97 93 102 97 128 85 -280 322 3 77 66 64 82 108 62 -281 322 3 90 79 81 89 121 89 -282 322 3 90 84 90 95 135 94 -283 322 3 83 73 69 101 114 62 -284 322 3 83 75 73 99 117 74 -285 322 3 87 79 76 100 127 85 -286 322 3 85 77 77 99 120 79 -287 322 3 80 74 66 100 119 78 -288 322 3 80 74 66 100 119 78 -289 322 3 82 76 71 101 116 68 -348 322 7 116 101 112 54 99 97 -349 322 7 124 110 123 59 113 109 -350 322 7 109 93 95 54 85 87 -240 323 3 85 75 83 85 107 70 -241 323 3 89 81 93 80 120 93 -242 323 3 99 97 118 77 136 121 -243 323 3 96 89 103 75 110 93 -244 323 3 75 59 57 68 72 45 -245 323 3 74 60 58 87 87 52 -246 323 3 87 84 98 83 128 98 -247 323 3 97 97 118 74 144 125 -248 323 3 90 86 95 78 122 99 -249 323 3 79 69 72 97 101 65 -250 323 3 81 74 81 94 123 88 -276 323 3 76 65 60 94 78 30 -277 323 3 95 89 92 93 126 91 -278 323 3 154 156 182 109 215 199 -279 323 3 132 129 145 114 205 174 -280 323 3 79 69 73 83 120 80 -281 323 3 95 88 99 82 152 109 -282 323 3 85 73 81 88 139 88 -283 323 3 89 84 91 88 137 96 -284 323 3 90 79 87 87 146 97 -285 323 3 88 80 84 85 144 94 -286 323 3 87 76 82 82 135 87 -287 323 3 86 79 87 84 131 88 -288 323 3 89 81 87 92 127 87 -289 323 3 79 72 67 103 108 61 -240 324 3 91 88 108 73 131 109 -241 324 3 101 102 130 73 140 122 -242 324 3 102 95 113 68 115 100 -243 324 3 76 61 60 66 73 46 -244 324 3 72 59 55 72 85 53 -245 324 3 88 86 104 77 127 97 -246 324 3 99 98 121 74 136 118 -247 324 3 90 83 89 84 113 88 -248 324 3 90 83 89 84 113 88 -249 324 3 73 62 55 109 91 54 -250 324 3 69 56 51 119 86 43 -276 324 3 76 65 60 94 78 30 -277 324 3 90 84 89 85 113 80 -278 324 3 130 130 147 101 209 196 -279 324 3 120 119 129 113 209 189 -280 324 3 79 70 74 77 136 86 -281 324 3 89 78 86 78 178 115 -282 324 3 86 73 77 77 151 92 -283 324 3 87 78 80 87 155 102 -284 324 3 83 72 76 86 134 86 -285 324 3 85 72 75 79 130 82 -286 324 3 82 70 75 84 128 80 -287 324 3 85 74 78 86 144 93 -288 324 3 83 71 71 96 132 86 -289 324 3 88 78 78 99 126 84 -240 325 3 90 86 116 75 134 108 -241 325 3 95 98 127 73 135 116 -242 325 3 98 92 104 70 114 95 -243 325 3 73 59 54 73 77 47 -244 325 3 77 68 71 76 98 66 -245 325 3 92 90 110 71 133 105 -246 325 3 96 94 116 76 130 105 -247 325 3 87 78 80 84 104 76 -248 325 3 81 71 72 86 103 70 -249 325 3 77 64 62 106 97 60 -250 325 3 72 59 44 122 86 42 -276 325 3 104 97 101 88 115 85 -277 325 3 109 103 109 91 120 83 -278 325 3 106 102 117 101 154 122 -279 325 3 94 88 87 97 156 121 -280 325 3 83 68 66 69 128 82 -281 325 3 79 65 61 55 95 59 -282 325 3 76 64 58 60 74 47 -283 325 3 80 69 70 84 133 83 -284 325 3 78 65 63 81 124 74 -285 325 3 81 66 64 80 125 75 -286 325 3 81 70 69 88 122 74 -287 325 3 82 72 73 89 120 71 -288 325 3 80 68 67 100 114 67 -289 325 3 78 62 57 107 108 65 -240 326 3 92 87 113 73 129 104 -241 326 3 97 96 124 71 131 116 -242 326 3 92 83 94 67 103 83 -243 326 3 72 56 50 69 69 40 -244 326 3 74 63 63 78 92 62 -245 326 3 94 92 109 74 135 109 -246 326 3 83 77 81 91 113 81 -247 326 3 73 61 52 102 89 51 -248 326 3 83 72 78 83 105 74 -249 326 3 92 85 99 73 119 93 -250 326 3 89 83 91 82 121 89 -276 326 3 133 129 145 87 160 140 -277 326 3 131 125 144 85 165 147 -278 326 3 104 93 102 91 143 118 -279 326 3 87 74 71 78 106 72 -280 326 3 74 58 50 35 50 28 -281 326 3 71 54 47 20 25 20 -282 326 3 75 65 59 61 57 35 -283 326 3 76 63 58 84 98 56 -284 326 3 76 61 59 91 106 60 -285 326 3 78 67 62 93 113 66 -286 326 3 81 72 74 88 130 80 -287 326 3 83 73 77 84 137 83 -288 326 3 82 72 75 87 125 72 -289 326 3 80 66 63 102 118 66 -389 326 1 116 107 128 68 151 128 -390 326 1 104 91 101 62 111 85 -391 326 1 104 91 101 62 111 85 -392 326 1 119 104 112 59 107 92 -393 326 1 113 95 110 52 87 80 -394 326 1 95 76 82 47 65 53 -395 326 1 86 70 70 67 83 53 -396 326 1 84 70 75 73 100 68 -397 326 1 81 69 68 63 82 53 -398 326 1 72 58 51 73 70 42 -399 326 1 69 56 46 84 77 35 -240 327 3 95 87 107 71 120 102 -241 327 3 102 97 119 72 127 109 -242 327 3 86 75 84 61 98 79 -243 327 3 68 54 47 59 68 39 -244 327 3 68 56 48 83 77 40 -245 327 3 84 78 87 85 112 83 -246 327 3 78 70 65 96 101 61 -247 327 3 69 54 38 115 85 39 -248 327 3 69 55 40 120 84 39 -249 327 3 77 68 63 105 98 58 -250 327 3 82 74 76 92 106 73 -277 327 3 122 115 122 97 156 133 -278 327 3 99 92 95 96 142 113 -279 327 3 81 71 65 69 93 65 -280 327 3 70 53 48 28 15 11 -281 327 3 71 55 49 34 12 9 -282 327 3 75 65 59 61 57 35 -283 327 3 78 66 61 91 107 58 -284 327 3 74 62 55 98 103 53 -285 327 3 76 66 59 95 111 58 -286 327 3 81 68 66 94 120 65 -287 327 3 80 69 65 87 115 71 -288 327 3 82 73 77 83 123 83 -289 327 3 80 70 65 94 114 64 -380 327 1 157 147 171 93 161 142 -381 327 1 119 100 109 57 94 95 -382 327 1 97 74 77 42 82 78 -383 327 1 111 96 103 57 88 84 -384 327 1 108 89 100 54 86 78 -385 327 1 105 84 91 47 77 73 -386 327 1 116 95 104 58 81 79 -387 327 1 147 137 161 89 165 145 -388 327 1 140 137 163 86 188 160 -389 327 1 106 95 109 57 110 95 -390 327 1 78 58 63 46 80 57 -391 327 1 93 77 78 60 83 56 -392 327 1 97 84 95 66 96 75 -393 327 1 91 74 78 63 89 68 -394 327 1 88 74 76 65 80 58 -395 327 1 85 72 76 65 99 71 -396 327 1 81 66 65 75 88 57 -397 327 1 73 63 56 80 88 49 -398 327 1 69 54 44 85 72 37 -399 327 1 69 56 41 98 80 39 -240 328 3 92 83 100 70 114 92 -241 328 3 104 99 122 71 125 108 -242 328 3 86 75 85 55 88 71 -243 328 3 67 52 44 58 65 38 -244 328 3 73 62 53 88 79 39 -245 328 3 84 77 81 88 114 82 -246 328 3 90 86 99 78 128 100 -247 328 3 82 74 82 89 106 69 -248 328 3 73 61 51 114 86 41 -249 328 3 67 54 32 129 83 39 -250 328 3 67 53 37 126 85 39 -277 328 3 85 76 72 98 126 86 -278 328 3 81 70 65 91 113 67 -279 328 3 79 66 65 64 79 51 -280 328 3 77 64 56 52 57 38 -281 328 3 75 62 58 76 80 43 -282 328 3 79 68 63 91 118 69 -283 328 3 73 65 59 95 103 50 -284 328 3 82 69 63 94 97 50 -285 328 3 82 69 63 94 97 50 -286 328 3 87 78 82 93 113 70 -287 328 3 90 77 80 82 114 80 -288 328 3 89 82 87 74 102 81 -289 328 3 82 72 71 100 118 75 -380 328 1 119 99 107 63 109 105 -381 328 1 104 81 85 46 76 72 -382 328 1 101 83 87 46 83 77 -383 328 1 98 81 85 49 87 77 -384 328 1 105 85 94 51 88 82 -385 328 1 107 87 96 49 90 86 -386 328 1 109 90 96 48 87 80 -387 328 1 110 90 101 55 94 89 -388 328 1 118 107 124 70 112 97 -389 328 1 135 131 152 79 111 88 -390 328 1 107 91 101 58 70 60 -391 328 1 100 86 94 59 73 62 -392 328 1 89 70 72 55 79 65 -393 328 1 88 74 73 71 91 64 -394 328 1 94 80 85 65 88 60 -395 328 1 90 76 83 67 99 70 -396 328 1 80 67 62 85 97 58 -397 328 1 84 77 73 86 111 74 -398 328 1 81 66 62 79 80 53 -399 328 1 74 58 49 94 82 45 -400 328 1 81 68 60 82 87 51 -240 329 3 84 75 75 75 100 76 -241 329 3 95 86 98 76 125 104 -242 329 3 79 67 69 64 73 63 -243 329 3 68 55 48 78 68 38 -244 329 3 74 62 50 101 84 46 -245 329 3 87 80 85 89 113 83 -246 329 3 91 88 108 75 129 105 -247 329 3 90 86 105 79 135 103 -248 329 3 83 75 76 94 122 81 -249 329 3 72 62 49 113 98 48 -250 329 3 71 59 44 118 92 47 -251 329 3 69 55 38 121 84 40 -380 329 1 92 74 76 62 82 74 -381 329 1 100 82 86 52 78 72 -382 329 1 101 83 90 52 84 78 -383 329 1 104 88 95 52 89 81 -384 329 1 103 86 94 55 92 86 -385 329 1 104 86 94 53 93 87 -386 329 1 107 91 99 53 92 88 -387 329 1 96 78 83 51 79 79 -388 329 1 119 107 123 70 103 82 -389 329 1 135 131 152 79 111 88 -390 329 1 139 131 158 79 128 90 -391 329 1 113 105 117 57 105 77 -392 329 1 87 64 64 44 58 54 -393 329 1 94 78 79 66 84 67 -394 329 1 98 81 89 56 86 67 -395 329 1 95 81 87 60 91 80 -396 329 1 85 75 74 78 113 69 -397 329 1 96 84 89 73 111 79 -398 329 1 93 79 81 64 98 70 -399 329 1 87 73 73 61 85 60 -400 329 1 87 71 68 68 80 60 -240 330 3 73 63 55 104 97 58 -241 330 3 71 58 46 111 85 46 -242 330 3 71 59 51 103 85 43 -243 330 3 72 59 49 107 86 43 -244 330 3 74 62 50 101 84 46 -245 330 3 75 64 55 106 98 59 -246 330 3 76 64 62 103 108 65 -247 330 3 80 70 70 99 113 70 -248 330 3 80 73 70 96 112 67 -249 330 3 78 66 56 103 97 52 -250 330 3 71 59 45 113 84 43 -251 330 3 71 62 47 118 93 46 -380 330 1 87 73 74 72 84 64 -381 330 1 94 79 85 65 83 72 -382 330 1 98 81 87 64 88 76 -383 330 1 101 84 92 55 88 84 -384 330 1 99 84 91 59 95 81 -385 330 1 101 86 92 60 97 88 -386 330 1 99 83 90 59 98 91 -387 330 1 96 81 85 59 90 80 -388 330 1 92 76 80 55 90 73 -389 330 1 144 139 165 87 112 85 -390 330 1 107 96 114 65 96 77 -391 330 1 101 88 100 62 89 71 -392 330 1 95 79 82 60 79 66 -393 330 1 99 80 83 55 77 65 -394 330 1 98 79 87 50 74 66 -395 330 1 92 75 80 57 94 71 -396 330 1 96 81 91 67 95 76 -397 330 1 96 82 92 60 82 71 -398 330 1 95 77 81 51 79 63 -399 330 1 96 80 87 45 70 56 -400 330 1 87 71 76 58 73 51 -240 331 3 71 57 42 123 85 39 -241 331 3 68 56 40 131 84 37 -242 331 3 73 61 48 102 88 44 -243 331 3 71 58 48 100 84 41 -244 331 3 68 56 35 124 82 39 -245 331 3 67 54 34 122 80 38 -246 331 3 75 65 62 99 106 61 -247 331 3 85 76 81 84 123 80 -248 331 3 80 68 63 97 104 62 -249 331 3 70 59 44 115 83 41 -250 331 3 70 58 42 122 78 37 -251 331 3 70 60 43 125 84 38 -380 331 1 97 81 84 64 75 53 -381 331 1 98 80 87 64 90 72 -382 331 1 95 77 79 66 91 70 -383 331 1 98 81 85 63 94 83 -384 331 1 97 81 87 61 90 77 -385 331 1 94 79 83 60 90 73 -386 331 1 93 75 79 61 92 75 -387 331 1 95 76 80 58 90 76 -388 331 1 93 78 82 56 88 74 -389 331 1 86 69 73 53 91 68 -390 331 1 90 72 72 58 83 67 -391 331 1 94 75 78 59 81 68 -392 331 1 100 80 83 59 83 69 -393 331 1 99 85 90 51 82 75 -394 331 1 98 80 86 64 86 70 -395 331 1 88 73 78 64 87 62 -396 331 1 92 78 81 61 103 72 -397 331 1 93 80 88 55 88 73 -398 331 1 93 72 80 46 71 58 -399 331 1 97 79 93 49 86 71 -400 331 1 92 76 82 52 72 58 -380 332 1 93 76 84 58 83 66 -381 332 1 87 71 73 55 71 49 -382 332 1 90 67 69 45 55 44 -383 332 1 93 75 79 51 76 63 -384 332 1 88 69 70 46 69 52 -385 332 1 88 67 68 44 67 52 -386 332 1 94 76 79 48 79 67 -387 332 1 94 76 79 48 79 67 -388 332 1 93 78 82 51 79 69 -389 332 1 95 80 85 58 79 69 -390 332 1 102 86 92 57 73 71 -391 332 1 100 84 93 61 81 76 -392 332 1 92 76 79 69 88 71 -393 332 1 90 76 80 67 84 69 -394 332 1 93 78 83 61 95 67 -395 332 1 88 73 78 64 87 62 -396 332 1 94 71 76 44 70 53 -397 332 1 94 75 80 45 77 64 -398 332 1 97 76 86 45 67 56 -399 332 1 95 75 85 47 70 60 -400 332 1 93 74 75 46 68 57 -380 333 1 94 75 82 52 82 71 -381 333 1 94 71 75 45 61 47 -382 333 1 89 69 71 39 56 46 -383 333 1 91 71 74 42 61 52 -384 333 1 87 65 67 40 49 42 -385 333 1 86 63 64 37 43 33 -386 333 1 89 66 67 37 53 47 -387 333 1 89 69 70 35 57 53 -388 333 1 94 81 86 57 91 66 -389 333 1 118 105 115 72 110 98 -390 333 1 108 96 102 74 103 86 -391 333 1 88 75 78 65 87 66 -392 333 1 93 80 85 62 86 68 -393 333 1 92 78 82 58 89 66 -394 333 1 97 77 83 50 68 56 -395 333 1 97 75 77 39 57 52 -396 333 1 96 74 80 41 64 53 -397 333 1 98 75 81 42 66 54 -398 333 1 97 77 82 41 62 51 -399 333 1 93 73 75 38 59 49 -400 333 1 93 73 75 38 59 49 -396 334 1 101 82 86 47 59 46 -397 334 1 92 72 76 40 58 50 -398 334 1 95 72 76 40 62 52 -399 334 1 93 72 78 40 60 48 -400 334 1 92 74 78 41 61 52 -185 346 4 80 69 69 85 110 70 -186 346 4 71 59 52 77 79 42 -185 347 4 85 71 73 76 86 58 -186 347 4 74 61 55 79 74 42 -187 347 4 75 67 61 80 95 56 -188 347 4 78 68 66 66 109 72 -184 348 4 80 70 69 71 92 59 -185 348 4 91 79 81 78 93 67 -186 348 4 76 62 57 84 77 43 -187 348 4 76 66 60 86 94 55 -188 348 4 84 72 69 81 103 71 -189 348 4 81 68 63 85 92 64 -184 349 4 74 60 55 70 81 49 -185 349 4 87 76 72 80 93 61 -186 349 4 74 63 58 81 80 45 -187 349 4 77 64 62 81 95 55 -188 349 4 81 68 64 94 102 62 -189 349 4 73 60 52 97 82 48 -184 350 4 82 71 72 80 104 64 -185 350 4 71 59 55 72 82 47 -186 350 4 75 58 55 74 87 52 -187 350 4 81 69 68 85 112 64 -188 350 4 77 63 59 83 90 48 -189 350 4 73 56 50 75 77 46 -184 351 4 80 73 73 85 101 65 -185 351 4 78 65 64 78 77 45 -186 351 4 72 60 51 79 75 43 -187 351 4 81 70 68 83 113 67 -188 351 4 79 67 67 81 107 62 -189 351 4 71 56 49 76 74 39 -184 352 4 86 82 81 92 116 77 -185 352 4 79 63 60 75 78 50 -186 352 4 75 57 53 74 70 37 -187 352 4 79 68 68 79 96 61 -188 352 4 83 71 74 81 112 72 -189 352 4 75 61 61 79 101 55 -183 353 4 84 73 70 80 103 66 -184 353 4 87 79 83 81 116 80 -185 353 4 85 71 73 78 94 64 -186 353 4 85 68 70 77 84 54 -187 353 4 89 79 79 77 88 63 -188 353 4 85 76 78 79 103 71 -189 353 4 80 71 71 84 111 68 -183 354 4 74 64 58 82 95 54 -184 354 4 82 68 69 85 100 65 -185 354 4 80 65 66 70 97 64 -186 354 4 83 70 70 68 97 68 -187 354 4 88 75 74 70 84 59 -188 354 4 82 69 63 80 81 48 -189 354 4 81 70 71 85 105 66 -183 355 4 75 63 58 77 83 48 -184 355 4 84 71 71 89 98 60 -185 355 4 73 59 57 76 85 49 -186 355 4 74 58 55 66 75 44 -187 355 4 75 58 53 70 64 38 -188 355 4 69 54 44 85 68 34 -371 358 7 101 95 111 74 118 91 -372 358 7 118 105 119 69 137 124 -373 358 7 110 105 118 70 134 120 -371 359 7 102 97 111 75 118 92 -372 359 7 106 97 108 70 120 100 -373 359 7 110 105 118 70 134 120 -374 359 7 112 107 122 73 136 120 -371 360 7 108 100 114 62 119 107 -372 360 7 104 88 94 54 95 81 -373 360 7 109 101 111 69 108 92 -372 361 7 102 85 91 53 94 86 -373 361 7 110 95 104 63 97 86 -372 362 7 105 93 103 56 102 94 -373 362 7 111 93 95 51 87 78 -295 370 5 69 56 56 58 95 56 -296 370 5 72 55 57 59 105 66 -297 370 5 74 58 61 61 113 69 -298 370 5 75 57 63 62 122 76 -299 370 5 73 57 60 59 114 67 -300 370 5 75 56 56 54 94 58 -301 370 5 72 52 54 52 85 55 -302 370 5 72 52 50 51 84 51 -303 370 5 71 53 53 56 89 55 -304 370 5 71 55 55 57 94 57 -305 370 5 70 52 52 54 84 50 -306 370 5 70 53 48 61 72 43 -295 371 5 73 56 56 58 85 51 -296 371 5 68 51 50 57 80 48 -297 371 5 75 58 61 61 110 69 -298 371 5 75 59 61 59 114 72 -299 371 5 74 59 61 58 112 66 -300 371 5 72 55 54 55 102 62 -301 371 5 71 53 51 53 86 54 -302 371 5 71 52 50 52 74 46 -303 371 5 70 52 46 51 78 46 -304 371 5 65 49 44 56 71 41 -305 371 5 66 49 42 61 59 33 -306 371 5 70 52 48 62 65 38 -295 372 5 66 52 46 56 69 41 -296 372 5 67 49 44 60 62 33 -297 372 5 70 54 49 60 79 45 -298 372 5 70 52 52 58 85 51 -299 372 5 73 57 59 56 101 62 -300 372 5 73 56 58 54 98 59 -301 372 5 68 52 50 57 75 43 -302 372 5 69 52 49 59 69 41 -303 372 5 69 50 44 54 65 37 -304 372 5 67 49 42 61 57 29 -305 372 5 68 50 44 63 62 35 -306 372 5 71 54 52 61 84 50 -399 372 5 65 49 42 60 58 30 -400 372 5 69 51 42 63 57 32 -401 372 5 68 50 40 66 59 34 -402 372 5 70 51 42 69 68 34 -403 372 5 74 54 48 66 74 44 -404 372 5 78 59 63 65 105 62 -405 372 5 81 66 71 65 111 71 -406 372 5 71 52 48 53 70 45 -407 372 5 67 51 43 66 75 43 -408 372 5 69 56 48 67 75 41 -409 372 5 71 56 47 60 61 37 -295 373 5 68 50 41 62 60 29 -296 373 5 68 50 41 62 60 29 -297 373 5 71 52 46 62 63 36 -298 373 5 69 48 41 59 58 30 -299 373 5 67 54 53 60 83 51 -300 373 5 70 53 54 56 86 52 -301 373 5 72 52 49 58 75 43 -302 373 5 72 52 50 59 79 49 -303 373 5 69 52 47 57 63 37 -304 373 5 68 52 46 60 72 39 -305 373 5 72 55 56 59 96 59 -306 373 5 73 58 60 57 100 64 -399 373 5 68 49 42 62 56 30 -400 373 5 70 51 46 66 57 30 -401 373 5 69 51 42 63 54 31 -402 373 5 67 49 39 65 59 29 -403 373 5 73 55 51 65 68 39 -404 373 5 78 60 65 68 106 63 -405 373 5 78 66 71 65 125 78 -406 373 5 66 49 45 50 62 38 -407 373 5 67 50 46 62 62 37 -408 373 5 70 55 46 73 72 40 -409 373 5 71 57 48 78 73 39 -295 374 5 67 51 45 62 64 31 -296 374 5 67 51 45 62 66 36 -297 374 5 68 49 45 62 59 30 -298 374 5 69 49 46 60 63 36 -299 374 5 71 54 49 57 74 45 -300 374 5 72 57 57 61 87 52 -301 374 5 72 55 56 60 93 56 -302 374 5 71 50 46 58 73 43 -303 374 5 67 52 44 60 66 36 -304 374 5 68 53 51 57 81 49 -305 374 5 69 51 49 57 72 45 -306 374 5 73 53 50 59 81 48 -399 374 5 68 50 41 70 59 29 -400 374 5 72 53 46 66 63 38 -401 374 5 69 50 41 57 58 33 -402 374 5 70 51 44 73 69 35 -403 374 5 75 59 57 71 86 53 -404 374 5 78 61 64 63 97 58 -405 374 5 74 57 61 59 113 69 -406 374 5 68 50 43 53 62 35 -407 374 5 67 50 46 64 55 32 -408 374 5 73 61 51 82 87 49 -295 375 5 68 50 45 60 65 36 -296 375 5 67 50 44 61 66 38 -297 375 5 70 49 45 61 69 38 -298 375 5 68 50 44 60 60 34 -299 375 5 71 51 43 58 66 38 -300 375 5 72 57 55 62 92 56 -301 375 5 70 57 59 60 100 60 -302 375 5 68 50 48 55 77 44 -303 375 5 69 50 43 60 60 33 -304 375 5 67 52 45 59 59 33 -305 375 5 68 50 45 60 54 31 -306 375 5 71 50 51 60 75 44 -399 375 5 69 50 42 67 61 33 -400 375 5 72 54 49 60 58 35 -401 375 5 70 51 43 51 48 31 -402 375 5 72 51 45 66 69 38 -403 375 5 74 58 55 62 84 51 -404 375 5 72 56 53 51 76 50 -405 375 5 69 49 43 56 74 41 -406 375 5 70 50 44 57 59 36 -407 375 5 69 53 43 66 65 36 -408 375 5 72 59 51 72 80 43 -295 376 5 68 50 46 62 64 38 -296 376 5 67 50 44 61 66 38 -297 376 5 68 51 46 61 69 39 -298 376 5 67 50 46 58 68 39 -299 376 5 69 49 43 59 60 31 -300 376 5 69 53 50 63 78 47 -301 376 5 73 54 57 58 90 58 -302 376 5 69 50 48 54 70 39 -303 376 5 69 51 45 57 65 39 -304 376 5 69 51 44 57 65 39 -305 376 5 67 48 41 59 56 33 -306 376 5 70 51 49 61 71 44 -399 376 5 68 51 38 64 57 32 -400 376 5 68 52 43 61 60 32 -401 376 5 67 52 46 61 58 35 -402 376 5 69 54 46 65 64 37 -403 376 5 71 53 50 62 78 45 -404 376 5 70 54 48 49 56 38 -405 376 5 68 48 40 59 55 31 -406 376 5 70 51 45 57 54 29 -407 376 5 68 54 44 67 71 38 -408 376 5 71 59 52 73 86 46 -295 377 5 68 50 43 62 64 34 -296 377 5 70 50 44 61 65 37 -297 377 5 67 51 42 62 65 37 -298 377 5 64 51 43 60 64 35 -299 377 5 68 51 45 64 65 37 -300 377 5 69 54 54 66 83 49 -301 377 5 74 54 56 58 90 54 -302 377 5 71 51 45 56 66 39 -303 377 5 66 50 42 60 59 33 -304 377 5 70 50 44 59 63 37 -305 377 5 67 48 41 61 56 32 -306 377 5 71 51 47 64 67 40 -400 377 5 69 52 45 66 60 32 -401 377 5 69 54 48 65 72 41 -402 377 5 69 53 49 65 74 43 -403 377 5 71 53 50 62 78 45 -404 377 5 69 50 48 57 60 34 -405 377 5 69 53 44 62 62 35 -406 377 5 72 54 46 61 63 36 -407 377 5 68 58 50 69 72 40 -408 377 5 74 60 52 73 85 49 -295 378 5 67 50 42 62 61 30 -296 378 5 69 50 44 61 63 34 -297 378 5 67 50 40 62 61 35 -298 378 5 66 51 43 64 62 32 -299 378 5 69 53 51 64 78 47 -300 378 5 73 56 61 64 108 67 -301 378 5 73 55 58 58 102 62 -302 378 5 69 52 46 56 76 44 -303 378 5 65 49 40 62 55 29 -304 378 5 70 50 42 60 61 35 -305 378 5 69 49 43 62 60 35 -306 378 5 69 50 45 62 67 37 -400 378 5 74 59 53 69 71 44 -401 378 5 72 55 47 61 71 45 -402 378 5 69 51 45 56 61 36 -403 378 5 72 54 46 62 65 38 -404 378 5 76 58 53 64 67 41 -405 378 5 79 68 62 64 78 52 -406 378 5 72 59 54 69 78 49 -407 378 5 71 58 49 72 74 41 -408 378 5 76 61 57 63 80 47 -295 379 5 68 49 43 64 62 31 -296 379 5 69 50 42 64 64 37 -297 379 5 67 49 46 60 65 36 -298 379 5 69 52 48 62 81 46 -299 379 5 71 55 57 62 91 55 -300 379 5 75 55 62 58 99 61 -301 379 5 72 55 54 55 89 52 -302 379 5 69 52 46 56 76 44 -303 379 5 67 49 42 60 61 32 -304 379 5 67 47 40 62 54 32 -305 379 5 68 51 44 64 58 34 -306 379 5 70 51 47 66 71 38 -400 379 5 68 56 43 66 70 40 -401 379 5 68 52 44 71 68 39 -402 379 5 70 52 43 65 62 34 -403 379 5 68 51 46 58 57 34 -404 379 5 72 54 44 61 59 35 -405 379 5 72 57 50 63 76 48 -406 379 5 75 58 54 67 83 53 -407 379 5 76 61 55 74 83 46 -408 379 5 76 59 57 68 82 49 -295 380 5 68 52 47 58 76 42 -296 380 5 69 50 51 59 79 43 -297 380 5 68 53 52 58 85 51 -298 380 5 71 56 56 56 95 58 -299 380 5 73 53 55 56 91 54 -300 380 5 70 52 51 56 77 44 -301 380 5 68 51 46 56 63 36 -302 380 5 69 50 43 59 64 36 -303 380 5 66 49 41 63 55 28 -304 380 5 66 49 41 63 55 28 -305 380 5 67 51 44 67 64 38 -306 380 5 70 55 51 65 90 50 -400 380 5 69 51 43 61 65 34 -401 380 5 66 49 39 65 63 32 -402 380 5 66 51 41 73 73 38 -403 380 5 69 53 45 64 60 37 -404 380 5 70 52 50 58 64 36 -405 380 5 74 59 51 61 70 39 -406 380 5 77 64 63 74 89 55 -407 380 5 79 69 64 90 106 60 -408 380 5 81 68 65 84 105 68 -295 381 5 71 51 46 57 65 38 -296 381 5 70 52 49 57 78 45 -297 381 5 67 52 49 56 82 50 -298 381 5 68 53 51 56 80 47 -299 381 5 70 52 49 57 75 42 -300 381 5 68 49 45 57 68 40 -301 381 5 67 48 42 57 60 34 -302 381 5 66 49 42 60 55 30 -303 381 5 66 51 41 65 57 29 -304 381 5 69 53 47 67 75 44 -305 381 5 73 57 56 61 96 59 -306 381 5 74 55 61 55 94 57 -400 381 5 70 50 42 58 66 38 -401 381 5 67 49 41 59 58 31 -402 381 5 67 51 44 68 72 37 -403 381 5 71 56 49 76 82 47 -404 381 5 75 59 54 69 89 52 -405 381 5 73 56 52 59 78 46 -406 381 5 70 56 52 63 75 46 -407 381 5 73 57 53 77 87 47 -408 381 5 80 64 60 80 85 55 -116 382 5 69 51 48 60 72 40 -117 382 5 69 51 42 58 59 35 -118 382 5 69 52 42 63 58 31 -119 382 5 67 50 45 65 58 29 -120 382 5 67 49 44 59 59 31 -121 382 5 67 51 45 60 59 32 -122 382 5 70 52 45 58 63 38 -123 382 5 69 50 43 57 59 31 -124 382 5 70 51 46 62 69 39 -125 382 5 67 51 41 59 75 45 -126 382 5 70 54 47 54 64 39 -127 382 5 70 54 48 50 70 43 -400 382 5 69 52 45 56 72 40 -401 382 5 69 52 45 59 78 42 -402 382 5 72 54 48 66 80 43 -403 382 5 71 55 47 71 90 48 -404 382 5 73 58 52 67 92 53 -405 382 5 72 56 53 57 84 51 -406 382 5 70 54 46 50 56 34 -407 382 5 70 51 45 64 55 32 -408 382 5 70 53 46 65 50 29 -116 383 5 68 50 45 57 65 36 -117 383 5 70 52 45 57 62 37 -118 383 5 68 53 42 60 58 34 -119 383 5 67 52 44 64 62 33 -120 383 5 69 51 44 62 53 28 -121 383 5 68 49 43 62 56 29 -122 383 5 69 54 45 63 65 36 -123 383 5 69 52 44 61 59 33 -124 383 5 70 51 44 64 63 35 -125 383 5 69 50 45 57 72 41 -126 383 5 70 54 48 53 73 43 -127 383 5 72 58 55 59 71 42 -400 383 5 70 53 45 60 70 37 -401 383 5 69 52 48 57 78 44 -402 383 5 70 56 48 67 82 48 -403 383 5 71 55 49 69 84 48 -404 383 5 72 55 51 64 81 48 -405 383 5 74 56 50 58 79 47 -406 383 5 69 55 46 58 66 38 -407 383 5 65 52 43 60 67 41 -408 383 5 72 52 46 61 58 34 -116 384 5 67 52 44 62 58 31 -117 384 5 69 52 41 58 63 35 -118 384 5 70 52 43 61 60 36 -119 384 5 67 52 44 64 62 33 -120 384 5 67 50 45 62 60 34 -121 384 5 68 51 43 63 56 31 -122 384 5 70 52 43 60 65 37 -123 384 5 70 51 47 55 67 39 -124 384 5 68 50 45 57 60 33 -125 384 5 70 53 44 61 69 38 -126 384 5 72 56 47 60 78 46 -127 384 5 73 59 52 70 95 54 -400 384 5 71 54 44 60 73 40 -401 384 5 69 56 48 66 79 46 -402 384 5 70 55 50 60 75 42 -403 384 5 69 53 45 63 77 45 -404 384 5 70 53 43 60 68 41 -405 384 5 70 54 49 64 77 44 -406 384 5 71 58 52 62 73 48 -407 384 5 71 58 52 62 73 48 -408 384 5 76 60 56 63 70 42 -116 385 5 69 50 41 57 59 33 -117 385 5 69 50 43 58 60 32 -118 385 5 71 52 43 62 60 31 -119 385 5 68 50 43 64 61 33 -120 385 5 68 51 45 60 63 35 -121 385 5 67 50 41 59 57 31 -122 385 5 67 51 43 63 56 31 -123 385 5 67 51 45 58 65 37 -124 385 5 67 49 43 55 55 30 -125 385 5 69 52 48 63 66 38 -126 385 5 71 56 47 69 83 44 -127 385 5 68 53 46 63 83 48 -228 385 4 82 64 66 80 71 44 -229 385 4 72 60 56 83 63 37 -116 386 5 68 49 45 56 57 33 -117 386 5 68 49 45 56 57 33 -118 386 5 68 50 43 61 56 30 -119 386 5 67 52 45 64 60 33 -120 386 5 67 50 44 61 59 30 -121 386 5 68 52 45 60 60 33 -122 386 5 69 52 46 62 63 34 -123 386 5 66 51 45 63 64 37 -124 386 5 67 49 44 56 67 36 -125 386 5 72 54 47 70 78 43 -126 386 5 71 57 48 69 88 46 -127 386 5 70 51 43 55 65 38 -228 386 4 82 67 74 76 96 64 -229 386 4 78 68 67 85 112 68 -230 386 4 80 66 66 87 94 57 -231 386 4 76 61 60 86 82 48 -116 387 5 70 50 44 56 63 37 -117 387 5 70 52 42 61 62 36 -118 387 5 72 52 47 59 68 39 -119 387 5 68 50 45 61 59 33 -120 387 5 67 50 42 60 57 30 -121 387 5 68 52 47 65 67 37 -122 387 5 68 54 46 62 77 45 -123 387 5 70 55 48 56 71 42 -124 387 5 73 54 51 64 86 47 -125 387 5 72 54 47 70 78 43 -126 387 5 69 52 46 67 78 45 -127 387 5 67 51 46 55 72 43 -228 387 4 71 53 54 64 89 55 -229 387 4 78 63 60 70 94 58 -230 387 4 84 71 72 78 98 65 -231 387 4 85 73 77 76 87 62 -116 388 5 71 51 44 58 66 38 -117 388 5 71 55 47 63 74 44 -118 388 5 71 55 51 56 79 47 -119 388 5 68 50 45 59 62 34 -120 388 5 70 53 48 66 71 40 -121 388 5 70 53 48 57 76 44 -122 388 5 69 52 48 58 72 43 -123 388 5 71 55 50 68 80 45 -124 388 5 69 49 44 53 66 37 -125 388 5 68 51 45 60 69 41 -126 388 5 69 55 47 59 73 44 -127 388 5 70 58 47 62 80 44 -228 388 4 68 51 47 65 66 39 -229 388 4 78 61 57 74 78 43 -230 388 4 87 75 76 74 96 65 -231 388 4 89 79 82 85 100 68 -232 388 4 75 60 56 79 79 45 -116 389 5 68 51 47 58 72 41 -117 389 5 70 54 50 62 80 46 -118 389 5 70 52 49 53 76 44 -119 389 5 71 53 50 57 77 45 -120 389 5 72 54 49 59 77 46 -121 389 5 67 51 46 54 68 40 -122 389 5 69 54 49 67 80 44 -123 389 5 69 51 45 56 69 38 -124 389 5 67 46 41 50 52 30 -125 389 5 67 51 45 52 64 37 -126 389 5 69 55 45 60 70 41 -127 389 5 70 55 47 58 78 45 -228 389 4 73 57 57 70 81 47 -229 389 4 79 63 64 74 103 58 -230 389 4 81 71 71 77 102 63 -231 389 4 81 71 67 86 102 68 -232 389 4 84 72 71 85 86 53 -116 390 5 71 53 48 58 71 38 -117 390 5 70 53 48 56 77 46 -118 390 5 71 51 47 53 72 42 -119 390 5 69 54 50 54 78 47 -120 390 5 72 53 48 53 76 46 -121 390 5 69 55 50 62 78 46 -122 390 5 71 57 54 65 87 49 -123 390 5 69 49 44 44 67 37 -124 390 5 67 48 42 53 53 30 -125 390 5 67 49 44 56 57 33 -126 390 5 70 52 45 56 66 38 -127 390 5 70 53 45 56 73 43 -228 390 4 79 68 68 75 98 61 -229 390 4 83 72 72 76 106 68 -230 390 4 84 71 69 85 103 59 -231 390 4 81 71 67 91 104 66 -232 390 4 79 69 62 92 97 61 -116 391 5 72 54 47 57 78 46 -117 391 5 68 53 48 57 72 41 -118 391 5 71 50 46 57 67 39 -119 391 5 66 50 44 54 63 38 -120 391 5 69 51 44 60 64 39 -121 391 5 75 57 55 66 89 52 -122 391 5 71 53 52 51 81 48 -123 391 5 68 49 44 46 57 34 -124 391 5 69 51 45 55 58 35 -125 391 5 70 49 45 65 58 32 -126 391 5 69 50 43 55 61 34 -127 391 5 68 52 44 54 62 36 -228 391 4 78 66 64 82 98 64 -229 391 4 83 70 69 83 101 67 -230 391 4 83 71 67 89 102 62 -231 391 4 81 70 66 96 106 61 -232 391 4 80 69 64 91 102 64 -116 392 5 71 54 50 54 81 48 -117 392 5 70 54 48 59 68 39 -118 392 5 71 50 47 62 63 35 -119 392 5 67 50 40 58 54 29 -120 392 5 69 53 47 70 70 39 -121 392 5 72 54 53 55 80 48 -122 392 5 68 48 42 45 59 36 -123 392 5 69 48 41 54 55 32 -124 392 5 69 51 44 56 61 37 -125 392 5 70 51 43 60 58 34 -126 392 5 66 49 41 59 57 33 -127 392 5 66 49 43 56 54 30 -228 392 4 90 75 78 83 109 71 -229 392 4 79 68 62 93 96 61 -230 392 4 72 61 52 104 89 48 -231 392 4 75 59 52 92 82 42 -232 392 4 80 67 64 90 93 57 -117 393 5 71 53 55 64 81 47 -118 393 5 72 56 54 58 93 52 -119 393 5 68 50 42 65 61 33 -120 393 5 71 56 55 66 86 49 -121 393 5 68 50 48 45 67 43 -122 393 5 65 46 41 54 45 27 -123 393 5 68 49 43 62 59 30 -124 393 5 66 50 43 58 57 31 -125 393 5 68 50 40 55 55 30 -126 393 5 67 49 42 62 56 28 -127 393 5 66 49 42 63 58 33 -228 393 4 88 74 74 88 99 65 -229 393 4 75 62 58 89 80 52 -230 393 4 71 57 46 101 76 40 -231 393 4 70 54 41 104 82 41 -232 393 4 75 60 51 87 77 46 -267 393 4 76 61 57 63 75 50 -268 393 4 77 60 57 67 98 61 -117 394 5 75 57 61 62 109 65 -118 394 5 67 53 49 49 74 44 -119 394 5 70 52 50 51 76 48 -120 394 5 68 45 40 49 49 29 -121 394 5 68 49 42 62 55 28 -122 394 5 69 52 47 65 64 34 -123 394 5 67 50 46 61 55 29 -124 394 5 70 50 42 60 53 30 -125 394 5 69 50 41 60 52 30 -126 394 5 69 49 41 65 55 29 -127 394 5 66 50 45 63 60 32 -267 394 4 73 63 60 79 89 53 -268 394 4 81 69 66 84 107 65 -269 394 4 75 64 57 86 101 60 -270 394 4 78 64 57 90 96 52 -271 394 4 85 75 72 99 100 60 -272 394 4 84 76 72 96 99 60 -117 395 5 67 53 49 49 74 44 -118 395 5 69 48 42 56 50 29 -119 395 5 67 48 42 57 48 26 -120 395 5 69 52 46 67 67 35 -121 395 5 70 52 49 62 70 43 -122 395 5 71 52 48 57 66 40 -123 395 5 71 53 47 59 62 34 -124 395 5 70 51 43 64 59 32 -125 395 5 69 53 47 63 64 35 -126 395 5 69 52 45 58 62 36 -127 395 5 67 50 43 59 57 33 -267 395 4 80 67 66 86 91 55 -268 395 4 87 77 77 85 109 72 -269 395 4 82 70 67 89 100 59 -270 395 4 75 62 55 103 82 43 -271 395 4 70 59 48 109 89 45 -272 395 4 80 71 72 89 102 64 -273 395 4 90 80 91 72 104 76 -267 396 4 89 80 80 91 116 77 -268 396 4 89 80 80 91 116 77 -269 396 4 92 83 84 90 119 80 -270 396 4 86 73 69 96 94 57 -271 396 4 76 61 54 92 75 36 -272 396 4 79 65 67 75 97 60 -273 396 4 88 76 82 68 114 83 -267 397 4 85 75 76 87 108 70 -268 397 4 89 79 79 83 94 66 -269 397 4 101 87 89 68 97 73 -270 397 4 84 70 65 84 88 58 -271 397 4 73 59 50 92 83 47 -272 397 4 87 75 75 78 106 74 -273 397 4 80 67 66 80 93 60 -267 398 4 83 71 72 84 106 65 -268 398 4 85 74 72 85 102 64 -269 398 4 84 70 65 84 86 62 -270 398 4 72 59 51 90 84 54 -271 398 4 73 61 54 94 76 40 -272 398 4 86 71 68 79 92 58 -273 398 4 83 69 65 67 94 60 -186 399 6 76 64 69 76 94 54 -187 399 6 81 69 72 69 104 66 -188 399 6 76 62 63 68 86 51 -267 399 4 82 71 69 79 102 64 -268 399 4 85 74 72 85 102 64 -269 399 4 83 71 68 90 89 52 -270 399 4 76 61 54 94 79 42 -271 399 4 72 56 46 91 78 43 -272 399 4 75 60 52 84 78 47 -273 399 4 76 62 59 77 86 52 -185 400 6 74 59 62 60 76 46 -186 400 6 76 64 69 76 94 54 -187 400 6 72 57 56 49 75 41 -188 400 6 70 51 46 35 33 18 -267 400 4 81 70 68 81 89 56 -268 400 4 77 68 64 93 109 61 -269 400 4 85 71 70 94 95 61 -270 400 4 79 65 58 95 85 52 -271 400 4 86 75 73 90 93 61 -272 400 4 82 73 70 88 77 53 -273 400 4 73 58 53 86 71 38 -185 401 6 76 61 60 69 91 49 -186 401 6 68 48 40 25 24 16 -187 401 6 66 45 38 17 10 8 -188 401 6 66 46 33 13 10 10 -269 401 4 81 67 65 92 88 57 -270 401 4 86 72 70 85 89 67 -271 401 4 84 73 76 101 92 60 -272 401 4 84 69 70 84 81 55 -273 401 4 72 55 48 80 64 36 -274 401 4 79 64 58 85 80 50 -186 402 6 69 48 42 26 29 19 -271 402 4 75 61 55 100 87 46 -272 402 4 69 54 46 88 66 35 -273 402 4 70 54 41 86 64 34 -274 402 4 79 64 58 85 80 50 +id b1 b2 b3 b4 b5 b7 +133 59 5 94 76 80 58 89 70 +134 59 5 91 76 77 56 81 61 +135 59 5 84 70 76 62 102 65 +136 59 5 79 65 75 64 123 78 +137 59 5 77 64 70 62 128 81 +138 59 5 77 61 67 61 119 75 +139 59 5 79 61 74 64 137 86 +140 59 5 77 61 70 61 126 79 +141 59 5 78 62 68 61 121 77 +142 59 5 77 60 65 61 118 77 +143 59 5 75 60 64 60 114 72 +144 59 5 75 59 60 59 104 68 +145 59 5 81 63 72 72 110 68 +133 60 5 79 65 64 63 89 51 +134 60 5 78 66 66 61 100 56 +135 60 5 80 63 66 60 96 60 +136 60 5 76 59 62 60 90 56 +137 60 5 73 59 60 58 93 56 +138 60 5 73 56 57 58 86 52 +139 60 5 75 60 64 59 113 72 +140 60 5 78 60 63 58 113 72 +141 60 5 77 58 61 59 108 68 +142 60 5 73 57 57 56 100 63 +143 60 5 75 58 57 55 97 61 +144 60 5 73 59 57 58 98 61 +145 60 5 75 60 63 59 104 62 +133 61 5 73 59 60 65 94 58 +134 61 5 74 55 58 57 95 59 +135 61 5 72 55 54 53 84 52 +136 61 5 75 55 55 58 85 52 +137 61 5 75 55 55 58 85 52 +138 61 5 72 52 51 64 75 43 +139 61 5 72 56 58 57 85 53 +140 61 5 74 59 61 58 101 62 +141 61 5 76 57 61 59 100 59 +142 61 5 73 55 58 54 85 52 +143 61 5 71 55 52 56 81 48 +144 61 5 75 57 55 56 90 55 +145 61 5 73 57 56 54 91 55 +133 62 5 75 58 54 59 89 52 +134 62 5 70 53 52 58 83 50 +135 62 5 69 54 51 57 77 46 +136 62 5 74 53 49 59 81 47 +137 62 5 71 52 44 69 67 39 +138 62 5 68 55 45 69 65 36 +139 62 5 74 56 57 56 88 52 +140 62 5 71 55 58 59 95 56 +141 62 5 72 54 54 55 85 57 +142 62 5 71 55 51 56 79 47 +143 62 5 72 54 51 55 75 48 +144 62 5 69 51 48 53 60 35 +145 62 5 69 51 46 54 63 36 +133 63 5 74 58 55 61 95 57 +134 63 5 70 56 52 68 78 47 +135 63 5 69 54 47 73 76 43 +136 63 5 72 55 46 71 73 40 +137 63 5 72 56 48 72 67 36 +138 63 5 68 55 47 72 71 38 +139 63 5 71 54 56 58 83 49 +140 63 5 71 54 56 58 90 54 +141 63 5 70 55 52 56 87 54 +142 63 5 71 52 48 53 71 42 +143 63 5 68 51 46 58 67 38 +144 63 5 70 56 50 64 73 40 +145 63 5 68 49 42 59 58 32 +134 64 5 74 62 64 73 109 66 +135 64 5 73 62 57 84 103 59 +136 64 5 73 60 52 84 102 54 +137 64 5 72 59 52 75 90 48 +138 64 5 68 55 47 72 71 38 +139 64 5 70 54 51 63 84 50 +140 64 5 73 56 57 58 93 59 +141 64 5 70 56 54 62 85 48 +142 64 5 72 54 52 65 72 41 +143 64 5 70 55 47 72 79 44 +144 64 5 71 61 57 75 93 53 +145 64 5 71 51 48 60 64 36 +134 65 5 80 66 74 74 111 69 +135 65 5 79 69 69 80 110 64 +136 65 5 74 63 61 80 112 62 +137 65 5 73 58 55 73 100 57 +138 65 5 70 57 52 71 79 43 +139 65 5 74 58 62 65 91 54 +140 65 5 75 58 61 62 102 62 +141 65 5 73 56 60 65 98 58 +142 65 5 73 57 55 67 93 55 +143 65 5 72 57 51 74 98 55 +144 65 5 71 57 55 68 90 53 +145 65 5 72 54 52 60 74 41 +138 80 7 87 75 80 71 107 73 +139 80 7 96 84 95 77 128 88 +140 80 7 94 86 99 78 138 89 +141 80 7 102 91 107 75 127 86 +138 81 7 98 88 96 79 139 98 +139 81 7 110 97 115 81 152 122 +140 81 7 125 115 135 76 139 125 +141 81 7 100 91 101 75 109 83 +138 82 7 94 80 89 74 136 99 +139 82 7 104 89 98 71 142 116 +140 82 7 135 129 148 78 179 176 +141 82 7 118 111 128 71 143 137 +138 83 7 86 74 74 81 119 66 +139 83 7 100 88 97 76 125 96 +140 83 7 131 125 147 78 183 178 +141 83 7 132 122 141 74 172 167 +138 84 7 112 100 110 88 132 101 +139 84 7 117 110 122 82 127 105 +140 84 7 130 123 144 79 182 177 +141 84 7 124 112 133 68 173 174 +146 84 7 95 85 95 62 116 95 +147 84 7 116 108 129 69 137 133 +148 84 7 126 118 144 73 143 132 +149 84 7 109 96 116 64 128 116 +150 84 7 121 108 124 74 107 83 +145 85 7 93 76 85 62 105 77 +146 85 7 113 97 114 62 121 112 +147 85 7 122 111 134 72 139 133 +148 85 7 122 116 134 72 140 131 +149 85 7 115 102 121 64 125 112 +150 85 7 133 122 141 73 109 89 +145 86 7 116 104 118 68 146 131 +146 86 7 125 111 127 67 144 140 +147 86 7 122 112 131 69 138 132 +148 86 7 117 106 126 65 115 108 +149 86 7 119 109 121 65 124 111 +150 86 7 114 99 109 61 108 91 +403 114 1 97 83 90 58 85 74 +404 114 1 99 81 88 51 77 65 +402 115 1 98 88 93 57 100 90 +403 115 1 99 86 91 57 90 74 +404 115 1 93 76 75 57 84 69 +405 115 1 83 67 68 55 85 66 +402 116 1 129 117 129 69 103 91 +403 116 1 97 85 88 64 93 73 +404 116 1 106 90 98 64 99 76 +405 116 1 105 94 100 64 103 88 +406 116 1 112 97 109 65 101 92 +407 116 1 104 94 109 60 92 80 +408 116 1 112 102 119 62 101 88 +401 117 1 124 105 116 54 120 117 +402 117 1 157 139 156 80 165 156 +403 117 1 94 87 96 78 115 82 +404 117 1 103 87 97 63 101 83 +405 117 1 118 105 117 69 106 88 +406 117 1 108 92 101 63 100 80 +407 117 1 110 102 120 68 127 102 +408 117 1 108 102 120 63 108 90 +409 117 1 110 98 111 58 116 103 +410 117 1 106 93 98 51 69 61 +400 118 1 92 77 76 57 72 54 +401 118 1 99 81 82 52 86 81 +402 118 1 117 104 116 61 128 128 +403 118 1 102 94 110 73 123 100 +404 118 1 83 70 73 60 92 71 +405 118 1 103 89 106 65 109 88 +406 118 1 84 66 68 49 73 64 +407 118 1 99 87 96 56 89 80 +408 118 1 111 99 110 57 93 87 +409 118 1 111 96 107 53 86 77 +410 118 1 104 89 90 46 88 83 +411 118 1 108 99 114 57 102 91 +412 118 1 99 86 93 56 83 76 +399 119 1 72 60 50 62 68 45 +400 119 1 81 68 60 67 80 59 +401 119 1 102 94 105 71 114 92 +402 119 1 102 94 105 71 114 92 +403 119 1 97 88 101 65 115 94 +404 119 1 97 83 89 60 90 61 +405 119 1 113 103 118 69 105 89 +406 119 1 94 78 85 55 87 69 +407 119 1 121 110 132 69 141 125 +408 119 1 149 136 154 77 150 149 +409 119 1 134 117 128 61 121 120 +410 119 1 96 76 77 38 58 55 +411 119 1 95 82 92 51 99 80 +412 119 1 109 96 113 70 99 86 +413 119 1 104 87 98 61 89 74 +399 120 1 83 68 71 66 63 39 +400 120 1 86 71 69 76 83 50 +401 120 1 96 87 95 75 109 76 +402 120 1 97 86 93 62 102 79 +403 120 1 98 85 95 66 98 79 +404 120 1 113 101 113 70 112 99 +405 120 1 98 85 96 59 93 81 +406 120 1 141 126 145 74 143 135 +407 120 1 159 147 168 81 154 147 +408 120 1 135 124 139 68 126 121 +409 120 1 107 87 95 55 90 82 +410 120 1 92 74 84 51 81 69 +411 120 1 110 99 117 66 107 95 +412 120 1 106 100 122 69 120 103 +413 120 1 100 87 97 55 95 81 +398 121 1 94 78 79 64 76 60 +399 121 1 95 83 84 65 80 64 +400 121 1 99 86 91 69 94 61 +401 121 1 103 92 102 68 106 81 +402 121 1 110 102 117 64 110 98 +403 121 1 114 105 117 73 124 100 +404 121 1 104 95 105 66 104 91 +405 121 1 102 87 92 55 95 87 +406 121 1 114 99 111 58 111 111 +407 121 1 128 112 128 61 107 104 +408 121 1 124 112 126 61 91 89 +409 121 1 104 90 94 59 88 81 +410 121 1 103 87 99 58 98 84 +411 121 1 110 97 112 62 105 94 +412 121 1 97 85 95 53 85 75 +397 122 1 102 90 93 75 95 68 +398 122 1 106 91 102 74 94 69 +399 122 1 111 98 111 68 97 80 +400 122 1 125 116 125 71 100 78 +401 122 1 107 95 104 64 94 76 +402 122 1 114 109 126 67 123 110 +403 122 1 121 115 133 75 130 108 +404 122 1 109 100 111 70 116 100 +405 122 1 98 86 92 59 86 75 +406 122 1 94 77 82 44 79 73 +407 122 1 96 79 84 43 88 80 +408 122 1 110 96 109 56 109 102 +409 122 1 109 96 109 58 99 92 +410 122 1 96 78 81 54 83 72 +411 122 1 104 88 97 56 91 78 +397 123 1 128 118 133 76 115 95 +398 123 1 117 102 118 70 103 82 +399 123 1 116 103 113 69 100 82 +400 123 1 128 118 131 71 97 86 +401 123 1 108 98 114 61 97 84 +402 123 1 118 112 131 67 110 96 +403 123 1 115 109 122 67 122 101 +404 123 1 104 99 113 71 107 83 +405 123 1 94 77 84 58 87 73 +406 123 1 99 87 96 55 81 65 +407 123 1 125 115 134 71 111 93 +408 123 1 132 122 140 76 134 118 +409 123 1 109 99 114 60 110 101 +410 123 1 102 84 95 51 86 74 +411 123 1 107 90 102 55 100 88 +397 124 1 112 94 103 54 95 84 +398 124 1 107 91 102 62 101 88 +399 124 1 113 102 114 68 114 98 +400 124 1 120 116 129 70 124 109 +401 124 1 126 122 141 72 131 113 +402 124 1 128 121 142 72 125 105 +403 124 1 121 117 136 74 114 94 +404 124 1 99 87 95 67 101 78 +405 124 1 91 74 81 63 107 80 +406 124 1 100 87 99 59 101 79 +407 124 1 119 109 126 67 121 106 +408 124 1 122 116 133 72 134 120 +409 124 1 102 95 109 58 106 95 +410 124 1 107 94 105 54 102 94 +399 125 1 106 102 118 68 116 102 +400 125 1 116 120 147 80 137 115 +401 125 1 126 123 147 78 131 108 +402 125 1 121 109 131 72 132 105 +403 125 1 121 117 136 74 114 94 +404 125 1 91 82 89 66 95 73 +405 125 1 81 68 67 61 96 71 +406 125 1 89 73 81 55 95 74 +407 125 1 105 94 107 60 113 100 +408 125 1 121 114 134 70 128 117 +409 125 1 110 100 119 61 107 95 +401 126 1 91 78 87 68 94 70 +402 126 1 89 75 76 66 97 74 +403 126 1 88 78 82 57 93 71 +404 126 1 93 82 86 60 93 76 +405 126 1 101 88 100 61 100 85 +406 126 1 110 98 115 62 113 98 +407 126 1 112 103 122 63 120 105 +408 126 1 111 98 115 59 113 98 +402 127 1 91 75 79 66 107 71 +403 127 1 95 84 89 71 113 90 +404 127 1 96 86 89 81 123 96 +405 127 1 114 102 116 68 126 111 +406 127 1 117 102 120 58 110 108 +407 127 1 120 107 126 64 117 103 +408 127 1 142 129 151 76 129 112 +404 128 1 88 77 79 86 114 80 +405 128 1 107 94 104 71 109 94 +406 128 1 106 89 100 55 94 92 +407 128 1 115 102 117 69 134 119 +406 129 1 92 76 77 66 108 81 +352 134 3 79 66 71 65 122 77 +353 134 3 82 67 77 73 131 83 +354 134 3 79 65 73 80 127 77 +355 134 3 77 65 64 80 109 63 +352 135 3 78 65 72 66 124 77 +353 135 3 81 68 78 77 137 84 +354 135 3 78 66 70 82 119 71 +355 135 3 71 57 50 76 79 45 +356 135 3 68 52 46 69 62 36 +357 135 3 74 59 56 72 85 50 +358 135 3 78 68 69 79 120 69 +359 135 3 83 69 74 76 124 73 +360 135 3 81 70 74 82 123 75 +352 136 3 81 67 78 78 138 84 +353 136 3 81 69 74 83 135 83 +354 136 3 75 63 56 82 99 58 +355 136 3 69 55 46 77 69 36 +356 136 3 68 52 43 73 56 30 +357 136 3 72 56 49 74 79 45 +358 136 3 78 68 69 79 120 69 +359 136 3 81 71 75 81 129 76 +360 136 3 85 75 78 82 123 73 +361 136 3 84 81 90 83 113 75 +362 136 3 84 83 98 88 126 89 +363 136 3 81 77 94 90 127 80 +352 137 3 81 68 72 87 121 75 +353 137 3 76 63 60 78 100 60 +354 137 3 71 56 46 76 75 40 +355 137 3 70 55 46 77 67 33 +356 137 3 67 54 45 75 62 34 +357 137 3 71 58 49 75 67 37 +358 137 3 78 68 69 80 124 73 +359 137 3 82 72 74 78 134 82 +360 137 3 88 81 90 77 137 93 +361 137 3 91 86 101 80 136 99 +362 137 3 83 76 85 83 122 85 +363 137 3 85 83 100 85 129 89 +352 138 3 72 58 52 79 81 47 +353 138 3 72 57 48 76 81 45 +354 138 3 72 55 47 80 74 38 +355 138 3 72 54 47 78 63 33 +356 138 3 69 53 44 77 56 28 +357 138 3 69 56 48 79 59 32 +358 138 3 76 66 59 80 99 55 +359 138 3 80 70 73 79 128 77 +360 138 3 84 76 86 80 126 87 +361 138 3 87 81 92 86 132 90 +362 138 3 83 75 82 80 134 84 +363 138 3 85 79 90 86 128 85 +352 139 3 73 57 50 78 73 41 +353 139 3 72 57 49 79 81 41 +354 139 3 71 57 50 79 75 37 +355 139 3 70 56 46 78 62 35 +356 139 3 69 58 47 80 61 35 +357 139 3 74 62 60 83 82 44 +358 139 3 76 64 59 83 87 50 +359 139 3 76 68 66 94 112 60 +360 139 3 77 69 60 96 106 64 +361 139 3 76 69 58 107 102 55 +362 139 3 78 70 68 98 120 70 +363 139 3 89 84 95 75 143 99 +352 140 3 69 55 51 77 79 42 +353 140 3 71 56 48 76 65 35 +354 140 3 73 55 48 79 62 34 +355 140 3 69 58 52 85 81 45 +356 140 3 78 67 69 88 123 72 +357 140 3 83 70 76 82 139 83 +358 140 3 76 68 66 90 111 61 +359 140 3 81 71 67 91 117 67 +360 140 3 80 69 69 100 111 59 +361 140 3 79 71 66 107 103 59 +362 140 3 85 74 75 85 128 79 +363 140 3 80 72 72 73 140 89 +352 141 3 73 58 55 81 92 50 +353 141 3 71 58 50 85 81 44 +354 141 3 73 60 50 91 77 40 +355 141 3 75 64 57 93 97 54 +356 141 3 81 71 73 85 137 80 +357 141 3 85 71 73 80 142 84 +358 141 3 78 68 65 90 113 66 +359 141 3 79 67 66 95 114 62 +360 141 3 85 72 74 93 133 77 +361 141 3 77 70 63 109 106 58 +362 141 3 80 73 70 89 119 74 +363 141 3 85 74 75 85 128 79 +352 142 3 74 63 56 96 104 56 +353 142 3 71 60 48 110 97 49 +354 142 3 70 59 47 111 88 41 +355 142 3 72 62 53 99 97 50 +356 142 3 79 68 64 89 122 71 +357 142 3 82 71 77 81 139 83 +358 142 3 78 68 67 86 123 75 +359 142 3 79 67 63 95 110 57 +360 142 3 85 72 76 91 132 77 +361 142 3 79 69 59 108 104 55 +362 142 3 82 76 75 95 119 72 +363 142 3 89 80 100 67 117 83 +352 143 3 76 64 61 91 105 58 +353 143 3 77 62 55 112 102 53 +354 143 3 73 60 47 117 91 42 +355 143 3 70 60 47 110 88 40 +356 143 3 76 64 58 101 100 55 +357 143 3 78 66 61 86 115 66 +358 143 3 82 70 73 81 121 75 +359 143 3 76 64 63 86 100 56 +360 143 3 81 71 69 90 116 67 +361 143 3 77 67 60 107 95 47 +362 143 3 82 74 69 102 109 62 +363 143 3 106 105 128 84 158 106 +352 144 3 77 66 65 77 114 67 +353 144 3 78 66 64 79 109 61 +354 144 3 76 61 56 91 97 56 +355 144 3 74 62 51 109 86 49 +356 144 3 77 64 58 98 78 46 +357 144 3 79 65 59 76 81 51 +358 144 3 78 61 62 63 106 66 +359 144 3 78 62 58 65 91 58 +360 144 3 81 72 72 81 104 65 +361 144 3 83 71 65 98 100 57 +362 144 3 80 73 66 99 112 65 +363 144 3 93 89 100 85 149 95 +352 145 3 77 67 67 79 113 69 +353 145 3 74 65 63 83 104 61 +354 145 3 79 65 64 89 102 60 +355 145 3 77 64 57 92 89 55 +356 145 3 79 64 59 64 63 47 +357 145 3 89 73 71 50 63 55 +358 145 3 78 62 63 65 96 63 +359 145 3 79 67 70 71 109 71 +360 145 3 87 74 76 87 120 75 +361 145 3 81 72 73 99 117 71 +362 145 3 84 76 76 87 137 88 +363 145 3 86 78 82 83 128 78 +352 146 3 85 73 73 72 100 67 +353 146 3 81 68 68 87 109 63 +354 146 3 78 67 62 87 95 49 +355 146 3 81 63 57 50 60 37 +356 146 3 91 71 66 39 57 48 +357 146 3 89 73 75 54 78 62 +358 146 3 79 66 68 62 108 71 +359 146 3 81 72 77 86 131 82 +360 146 3 81 72 77 86 131 82 +361 146 3 79 71 70 97 131 75 +362 146 3 85 74 84 77 145 94 +363 146 3 86 79 86 78 137 84 +352 147 3 86 73 76 90 100 70 +353 147 3 77 65 60 83 96 60 +354 147 3 76 65 57 67 85 51 +355 147 3 77 61 52 70 71 40 +356 147 3 80 68 60 66 74 48 +357 147 3 82 67 69 70 83 49 +358 147 3 79 66 63 68 88 61 +359 147 3 91 77 83 71 115 84 +360 147 3 87 77 79 85 122 85 +361 147 3 84 76 80 86 135 80 +362 147 3 84 74 83 74 139 88 +363 147 3 82 78 84 74 138 86 +352 148 3 88 75 76 92 99 57 +353 148 3 85 69 64 63 70 43 +354 148 3 81 65 61 58 68 47 +355 148 3 72 59 52 75 82 46 +356 148 3 74 62 54 65 81 50 +357 148 3 82 67 69 70 83 49 +358 148 3 86 70 67 66 85 62 +359 148 3 108 90 99 60 100 87 +360 148 3 110 93 103 66 101 88 +361 148 3 86 76 75 98 108 63 +362 148 3 84 73 73 92 130 79 +363 148 3 85 75 85 74 139 86 +352 149 3 100 84 84 68 97 79 +353 149 3 91 73 70 58 70 55 +354 149 3 80 63 60 69 82 55 +355 149 3 70 56 50 66 84 49 +356 149 3 73 59 52 61 81 48 +357 149 3 80 64 64 67 89 60 +358 149 3 82 66 66 55 86 63 +359 149 3 93 79 81 52 89 71 +360 149 3 107 87 93 64 93 73 +361 149 3 79 67 60 94 85 44 +362 149 3 76 67 61 101 110 61 +363 149 3 84 71 81 81 134 85 +264 169 5 71 50 43 49 65 40 +265 169 5 69 53 44 53 68 39 +266 169 5 69 50 46 57 72 39 +267 169 5 68 50 44 56 54 32 +268 169 5 70 52 48 51 57 35 +269 169 5 76 63 56 65 78 49 +270 169 5 75 62 61 67 98 59 +271 169 5 74 57 56 67 87 49 +272 169 5 72 55 50 60 66 38 +273 169 5 74 58 58 64 98 58 +274 169 5 74 59 59 63 100 63 +102 170 1 82 64 57 75 75 48 +103 170 1 87 72 74 64 90 68 +104 170 1 104 89 96 54 92 80 +264 170 5 70 50 41 48 56 35 +265 170 5 68 51 43 54 64 37 +266 170 5 68 56 49 56 70 40 +267 170 5 68 50 43 50 52 35 +268 170 5 70 53 46 57 64 38 +269 170 5 70 56 52 60 78 46 +270 170 5 71 52 48 58 81 48 +271 170 5 73 54 48 58 72 41 +272 170 5 70 55 57 61 89 54 +273 170 5 78 58 65 61 104 64 +274 170 5 74 60 64 60 100 63 +100 171 1 97 79 78 60 71 50 +101 171 1 95 76 77 59 76 54 +102 171 1 112 96 103 69 97 80 +103 171 1 99 82 87 58 94 75 +104 171 1 103 89 100 61 94 78 +264 171 5 68 50 44 53 62 34 +265 171 5 68 53 50 62 75 41 +266 171 5 71 56 53 63 76 45 +267 171 5 69 52 48 55 60 37 +268 171 5 68 49 41 56 48 25 +269 171 5 68 52 45 62 58 31 +270 171 5 69 50 44 59 62 35 +271 171 5 72 53 49 61 72 39 +272 171 5 73 56 55 60 90 55 +273 171 5 76 58 61 59 99 62 +274 171 5 70 56 59 58 93 54 +294 171 6 74 59 61 63 110 70 +295 171 6 73 58 59 64 105 65 +296 171 6 75 61 60 66 116 71 +297 171 6 78 60 62 66 115 71 +298 171 6 75 59 56 64 103 63 +299 171 6 75 60 62 63 108 65 +300 171 6 75 59 63 66 101 61 +301 171 6 74 57 56 63 94 55 +98 172 1 99 80 86 57 93 68 +99 172 1 99 79 79 45 63 54 +100 172 1 100 75 78 37 57 46 +101 172 1 97 73 78 48 62 45 +102 172 1 111 100 108 68 101 88 +103 172 1 111 97 107 65 98 86 +104 172 1 100 87 96 63 94 81 +264 172 5 69 53 52 60 77 44 +265 172 5 74 59 63 69 94 56 +266 172 5 71 56 53 63 76 45 +267 172 5 73 58 54 59 76 49 +268 172 5 68 50 40 54 49 27 +269 172 5 67 48 42 61 59 33 +270 172 5 66 51 45 60 62 33 +271 172 5 70 54 50 64 70 37 +272 172 5 72 56 55 62 84 51 +273 172 5 74 58 64 60 98 60 +274 172 5 72 58 60 60 93 54 +293 172 6 75 62 62 64 115 72 +294 172 6 74 59 58 62 115 73 +295 172 6 75 58 59 61 107 65 +296 172 6 76 58 62 62 115 71 +297 172 6 73 59 63 60 111 72 +298 172 6 75 61 65 59 117 73 +299 172 6 77 59 62 64 113 70 +300 172 6 75 58 63 62 108 68 +301 172 6 81 64 71 58 133 92 +96 173 1 114 105 122 76 120 93 +97 173 1 134 129 148 80 132 107 +98 173 1 131 114 139 71 119 98 +99 173 1 116 103 116 61 94 80 +100 173 1 98 78 84 42 65 54 +101 173 1 95 71 72 39 59 51 +102 173 1 111 100 108 68 101 88 +103 173 1 109 97 108 65 99 91 +104 173 1 98 82 88 57 96 84 +264 173 5 73 57 54 65 86 53 +265 173 5 77 63 69 72 109 66 +266 173 5 73 58 58 66 88 55 +267 173 5 76 57 55 59 81 54 +268 173 5 68 53 44 52 62 36 +269 173 5 66 49 42 60 60 35 +270 173 5 68 51 45 59 62 32 +271 173 5 69 55 52 60 77 43 +272 173 5 73 57 58 63 95 56 +273 173 5 75 60 63 63 105 62 +274 173 5 74 61 65 63 112 69 +293 173 6 74 62 63 65 117 70 +294 173 6 75 60 65 64 122 79 +295 173 6 75 58 62 60 110 74 +296 173 6 76 59 63 60 115 71 +297 173 6 77 64 69 62 125 82 +298 173 6 75 63 69 60 114 75 +299 173 6 79 65 73 63 126 84 +300 173 6 77 66 74 61 136 93 +301 173 6 77 65 79 57 141 102 +94 174 1 135 119 140 70 182 189 +95 174 1 113 95 110 62 116 108 +96 174 1 124 119 136 78 146 115 +97 174 1 149 154 185 103 187 154 +98 174 1 155 161 203 110 186 156 +99 174 1 149 152 189 104 178 150 +100 174 1 111 102 113 69 100 79 +101 174 1 95 76 79 50 71 54 +102 174 1 95 81 87 58 90 64 +103 174 1 107 94 107 66 105 89 +104 174 1 109 93 107 59 89 82 +105 174 1 104 90 99 56 90 79 +264 174 5 75 58 58 64 85 53 +265 174 5 76 61 63 66 95 59 +266 174 5 77 63 68 67 109 68 +267 174 5 75 57 60 57 89 57 +268 174 5 71 56 53 54 76 46 +269 174 5 69 52 48 61 75 46 +270 174 5 70 53 44 59 65 35 +271 174 5 69 54 52 59 68 39 +272 174 5 73 56 57 61 91 53 +273 174 5 74 60 64 63 102 60 +274 174 5 76 61 68 63 118 74 +293 174 6 75 61 61 66 113 68 +294 174 6 74 60 61 63 112 70 +295 174 6 75 57 64 61 115 78 +296 174 6 77 63 70 62 126 83 +297 174 6 78 64 70 60 130 87 +298 174 6 79 66 73 59 111 75 +299 174 6 78 65 73 59 111 77 +300 174 6 77 69 79 62 139 98 +301 174 6 81 70 81 60 152 107 +92 175 1 96 80 86 40 65 61 +93 175 1 101 82 88 57 102 92 +94 175 1 103 87 94 60 119 111 +95 175 1 109 95 101 60 102 91 +96 175 1 115 105 119 72 121 105 +97 175 1 139 136 164 94 166 133 +98 175 1 147 155 191 104 207 163 +99 175 1 143 146 179 100 196 163 +100 175 1 110 100 112 75 105 79 +101 175 1 97 84 93 62 90 70 +102 175 1 100 83 91 58 94 77 +103 175 1 104 88 98 58 102 90 +104 175 1 113 98 111 59 109 101 +105 175 1 115 101 113 58 110 102 +264 175 5 76 58 62 62 95 60 +265 175 5 74 59 64 66 114 69 +266 175 5 79 65 74 67 117 76 +267 175 5 79 64 69 58 103 68 +268 175 5 76 60 64 56 84 52 +269 175 5 70 53 51 58 87 51 +270 175 5 69 55 45 60 73 42 +271 175 5 68 55 46 62 69 41 +272 175 5 73 56 57 61 91 53 +273 175 5 74 57 64 58 101 62 +274 175 5 78 59 65 61 114 74 +293 175 6 76 60 66 63 117 74 +294 175 6 76 60 64 63 115 73 +295 175 6 78 64 72 65 134 87 +296 175 6 78 64 73 64 134 88 +297 175 6 77 62 67 61 121 78 +298 175 6 78 61 67 55 114 77 +299 175 6 79 65 72 56 113 80 +300 175 6 80 69 81 60 138 101 +301 175 6 81 69 83 61 148 107 +91 176 1 94 73 80 46 67 60 +92 176 1 92 69 73 30 38 37 +93 176 1 91 74 73 39 51 45 +94 176 1 101 84 85 48 61 50 +95 176 1 103 88 96 58 98 82 +96 176 1 108 90 101 56 102 100 +97 176 1 112 98 108 62 114 100 +98 176 1 120 116 129 80 151 122 +99 176 1 128 120 141 82 154 117 +100 176 1 102 85 99 62 105 77 +101 176 1 100 90 95 61 92 75 +102 176 1 104 90 100 61 95 82 +103 176 1 89 72 73 42 59 54 +104 176 1 95 77 78 44 64 62 +105 176 1 115 102 109 59 108 104 +264 176 5 74 61 64 65 108 67 +265 176 5 73 58 61 64 88 53 +266 176 5 81 65 76 63 123 78 +267 176 5 81 64 71 57 90 64 +268 176 5 74 58 57 57 83 51 +269 176 5 70 56 50 60 71 42 +270 176 5 69 55 48 63 67 37 +271 176 5 71 54 47 59 71 45 +272 176 5 75 57 61 57 89 53 +273 176 5 77 58 63 62 107 65 +274 176 5 76 62 68 62 114 72 +293 176 6 76 59 63 64 124 80 +294 176 6 77 59 64 67 130 83 +295 176 6 80 66 73 69 143 93 +296 176 6 76 66 74 67 137 88 +297 176 6 78 63 69 65 123 78 +298 176 6 79 64 69 60 116 77 +299 176 6 78 65 73 59 122 85 +300 176 6 80 68 80 60 139 99 +301 176 6 84 71 84 61 143 103 +91 177 1 104 82 91 45 61 54 +92 177 1 93 68 67 33 37 37 +93 177 1 94 75 76 36 42 36 +94 177 1 102 83 84 45 69 60 +95 177 1 102 82 92 50 80 71 +96 177 1 107 89 99 59 98 86 +97 177 1 104 89 100 64 89 77 +98 177 1 110 97 106 71 110 85 +99 177 1 101 88 100 60 99 79 +100 177 1 96 82 90 52 72 63 +101 177 1 107 89 100 53 85 82 +102 177 1 105 87 95 51 82 73 +103 177 1 105 87 95 51 82 73 +264 177 5 74 58 59 58 97 58 +265 177 5 72 56 58 59 97 56 +266 177 5 79 63 71 61 113 75 +267 177 5 83 67 69 58 91 66 +268 177 5 81 62 67 59 94 63 +269 177 5 72 57 60 59 92 57 +270 177 5 72 56 57 59 81 47 +271 177 5 71 54 48 59 77 44 +272 177 5 72 57 59 61 86 50 +273 177 5 74 56 61 61 107 63 +274 177 5 75 59 65 59 106 70 +293 177 6 77 59 62 64 113 73 +294 177 6 76 64 68 67 123 78 +295 177 6 80 67 71 68 125 81 +296 177 6 79 66 77 67 133 89 +297 177 6 78 63 69 65 123 78 +298 177 6 78 62 65 63 124 81 +299 177 6 76 60 64 60 119 80 +300 177 6 81 66 78 61 138 96 +301 177 6 84 74 88 62 148 105 +92 178 1 102 86 90 48 65 59 +93 178 1 99 76 80 39 54 49 +94 178 1 96 72 74 36 44 42 +95 178 1 92 73 74 43 49 44 +96 178 1 100 86 94 58 91 75 +97 178 1 105 85 94 58 89 76 +98 178 1 101 91 99 67 102 87 +99 178 1 99 82 81 55 73 61 +100 178 1 136 134 152 75 119 113 +101 178 1 138 124 142 67 106 99 +102 178 1 108 94 101 59 118 103 +264 178 5 74 58 62 57 99 62 +265 178 5 74 57 62 59 96 60 +266 178 5 76 61 63 58 82 53 +267 178 5 80 65 66 59 97 62 +268 178 5 77 58 64 61 90 59 +269 178 5 73 60 64 62 100 60 +270 178 5 72 58 57 55 81 49 +271 178 5 69 51 45 57 66 38 +272 178 5 69 55 49 62 78 49 +273 178 5 71 55 54 60 88 53 +274 178 5 76 59 62 63 93 55 +293 178 6 76 65 69 57 111 75 +294 178 6 80 66 73 59 122 81 +295 178 6 83 68 78 59 126 86 +296 178 6 82 69 79 59 128 88 +297 178 6 78 63 69 64 129 86 +298 178 6 78 61 65 61 122 83 +299 178 6 80 69 79 61 139 97 +300 178 6 80 69 79 61 139 97 +301 178 6 81 72 85 63 138 102 +92 179 1 111 91 102 56 91 79 +93 179 1 107 87 96 52 82 74 +94 179 1 102 83 90 45 65 59 +95 179 1 99 79 83 45 59 51 +96 179 1 99 85 85 62 75 66 +97 179 1 101 84 92 65 92 76 +98 179 1 105 93 97 58 85 72 +99 179 1 128 119 129 68 108 98 +100 179 1 163 168 194 89 145 144 +93 180 1 109 93 104 57 91 80 +94 180 1 108 90 100 58 94 81 +95 180 1 104 90 97 63 88 75 +96 180 1 101 84 86 63 80 71 +97 180 1 102 84 92 68 90 73 +98 180 1 106 95 101 55 84 76 +93 181 1 114 95 110 50 98 87 +94 181 1 110 91 99 60 98 84 +95 181 1 100 84 92 69 94 75 +96 181 1 104 89 97 66 89 79 +94 182 1 99 81 85 70 93 76 +192 188 6 68 48 36 15 15 13 +193 188 6 66 46 37 16 15 11 +194 188 6 66 46 35 14 13 13 +195 188 6 66 47 36 15 14 12 +196 188 6 66 46 36 14 13 11 +197 188 6 68 45 36 15 14 14 +198 188 6 64 45 35 14 12 13 +199 188 6 66 47 35 13 12 10 +200 188 6 65 47 35 13 13 11 +201 188 6 66 45 35 15 13 13 +202 188 6 64 44 34 15 12 12 +203 188 6 66 46 34 15 14 11 +204 188 6 65 46 35 15 13 13 +192 189 6 66 46 36 15 14 12 +193 189 6 68 46 36 15 14 11 +194 189 6 67 45 36 15 15 13 +195 189 6 65 47 36 15 14 11 +196 189 6 67 44 37 15 15 12 +197 189 6 67 47 37 15 13 12 +198 189 6 67 45 37 15 13 13 +199 189 6 64 46 33 15 13 12 +200 189 6 65 46 35 15 14 11 +201 189 6 66 44 36 15 14 12 +202 189 6 66 44 34 15 13 9 +203 189 6 66 46 36 15 12 10 +204 189 6 66 46 36 15 13 13 +193 190 6 69 46 36 14 13 12 +194 190 6 67 46 34 16 14 12 +195 190 6 67 46 36 15 14 14 +196 190 6 65 45 34 15 14 11 +197 190 6 66 48 39 16 14 10 +198 190 6 67 47 36 15 15 11 +199 190 6 64 45 35 15 14 14 +200 190 6 65 44 34 15 14 11 +201 190 6 66 45 36 15 13 13 +202 190 6 66 46 35 15 12 10 +203 190 6 64 46 36 14 13 11 +204 190 6 66 46 33 15 14 12 +193 191 6 68 47 36 15 15 11 +194 191 6 67 47 35 15 14 13 +195 191 6 68 46 37 14 13 11 +196 191 6 65 46 33 14 15 13 +197 191 6 66 46 39 15 14 12 +198 191 6 66 47 34 16 14 11 +199 191 6 66 45 36 15 13 12 +200 191 6 66 45 35 14 13 13 +201 191 6 66 46 35 14 12 11 +202 191 6 65 46 37 14 13 12 +203 191 6 65 46 34 15 15 11 +204 191 6 66 46 31 15 14 11 +193 192 6 66 47 36 15 14 12 +194 192 6 68 46 36 14 14 12 +195 192 6 68 46 37 14 13 11 +196 192 6 66 46 36 15 15 14 +197 192 6 68 48 39 15 13 12 +198 192 6 66 45 34 15 14 11 +199 192 6 67 46 34 15 13 12 +200 192 6 66 45 36 13 14 13 +201 192 6 68 45 35 14 12 10 +202 192 6 66 45 37 15 13 12 +203 192 6 66 45 33 15 14 12 +204 192 6 67 45 33 15 13 13 +194 193 6 66 46 35 15 14 13 +195 193 6 65 46 37 16 14 13 +196 193 6 67 47 37 14 15 11 +197 193 6 67 45 36 14 13 11 +198 193 6 64 47 33 15 14 14 +199 193 6 64 47 33 15 14 14 +200 193 6 67 44 37 14 15 11 +201 193 6 66 45 35 15 12 12 +202 193 6 66 46 35 14 12 13 +203 193 6 65 45 35 14 13 13 +204 193 6 66 45 35 15 14 12 +194 194 6 67 48 34 14 14 11 +195 194 6 67 45 36 16 13 11 +196 194 6 66 45 34 15 16 12 +197 194 6 67 47 37 15 13 12 +198 194 6 65 45 35 15 14 13 +199 194 6 65 45 34 15 14 11 +200 194 6 66 46 35 15 13 13 +201 194 6 67 44 36 15 14 14 +202 194 6 67 46 34 14 13 11 +203 194 6 66 46 35 15 13 12 +204 194 6 65 45 34 15 14 11 +194 195 6 67 46 35 15 15 12 +195 195 6 66 46 38 15 13 10 +196 195 6 68 47 34 15 15 12 +197 195 6 66 46 36 14 13 12 +198 195 6 65 46 33 15 15 10 +199 195 6 66 45 36 15 12 11 +200 195 6 66 45 33 14 14 15 +201 195 6 65 45 36 14 13 12 +202 195 6 66 45 35 15 14 10 +203 195 6 65 44 35 15 14 12 +204 195 6 66 47 36 14 14 13 +195 196 6 65 44 35 16 15 13 +196 196 6 67 45 37 15 14 13 +197 196 6 67 46 35 15 14 12 +198 196 6 66 46 34 15 15 11 +199 196 6 65 47 36 15 14 12 +200 196 6 67 45 35 15 14 13 +201 196 6 65 45 36 14 13 12 +202 196 6 64 45 35 15 15 11 +203 196 6 66 46 34 15 15 13 +294 227 4 86 73 78 55 73 53 +295 227 4 83 69 71 64 83 60 +296 227 4 86 71 70 69 85 62 +297 227 4 85 70 70 66 90 67 +298 227 4 89 74 77 64 80 60 +289 228 4 80 69 74 70 107 63 +290 228 4 80 71 79 64 107 73 +291 228 4 88 74 84 61 102 78 +292 228 4 95 82 93 56 90 70 +293 228 4 89 76 85 64 89 62 +294 228 4 83 70 71 73 90 61 +295 228 4 83 70 71 73 90 61 +296 228 4 86 71 73 73 90 62 +297 228 4 88 73 78 73 99 72 +298 228 4 92 78 83 78 102 75 +290 229 4 84 71 76 59 76 54 +291 229 4 87 75 84 62 102 69 +292 229 4 94 82 92 57 98 82 +293 229 4 92 82 93 64 102 76 +294 229 4 90 80 88 68 98 69 +295 229 4 93 81 88 68 98 72 +296 229 4 93 79 88 72 107 77 +297 229 4 98 84 96 66 110 84 +298 229 4 94 81 89 58 98 79 +290 230 4 79 63 66 62 83 60 +291 230 4 76 63 66 74 101 61 +292 230 4 89 74 81 61 98 73 +293 230 4 82 69 74 57 84 65 +294 230 4 85 70 75 52 77 58 +295 230 4 91 71 71 48 69 55 +296 230 4 86 68 69 53 81 58 +297 230 4 96 82 93 61 102 78 +298 230 4 100 90 102 62 95 80 +290 231 4 86 71 80 61 115 79 +291 231 4 75 60 60 74 89 53 +292 231 4 83 67 67 65 88 56 +133 244 4 69 56 44 71 72 38 +134 244 4 68 54 43 73 71 38 +135 244 4 73 59 53 80 82 45 +136 244 4 73 59 56 84 85 45 +137 244 4 69 61 50 83 92 48 +138 244 4 87 76 77 91 109 70 +139 244 4 93 82 79 113 113 72 +140 244 4 75 59 60 84 90 47 +133 245 4 73 60 53 77 93 51 +134 245 4 72 59 52 84 90 47 +135 245 4 76 66 58 87 104 58 +136 245 4 76 66 67 88 109 63 +137 245 4 80 67 67 82 116 67 +138 245 4 77 68 63 90 114 66 +139 245 4 88 81 73 107 115 79 +140 245 4 75 64 56 94 92 49 +133 246 4 73 60 53 77 93 51 +134 246 4 77 64 60 85 106 60 +135 246 4 77 68 66 85 112 65 +136 246 4 79 68 70 87 119 65 +137 246 4 81 72 74 85 128 77 +138 246 4 77 65 65 86 104 55 +139 246 4 81 68 64 81 83 51 +140 246 4 81 66 61 100 75 43 +134 247 4 80 71 73 83 123 73 +135 247 4 78 67 67 78 112 64 +136 247 4 77 64 62 86 108 59 +137 247 4 79 70 70 89 122 70 +138 247 4 80 65 66 80 114 68 +139 247 4 79 64 61 79 81 50 +140 247 4 75 64 59 90 79 43 +141 247 4 70 58 47 101 78 37 +250 247 4 69 55 48 63 68 38 +251 247 4 77 67 71 70 98 61 +134 248 4 79 68 68 79 118 70 +135 248 4 78 62 66 75 106 64 +136 248 4 86 74 78 74 110 72 +137 248 4 87 74 79 69 110 71 +138 248 4 82 71 71 76 106 69 +139 248 4 81 70 67 92 91 50 +140 248 4 81 72 67 91 100 56 +141 248 4 80 67 62 87 89 55 +250 248 4 80 63 60 64 81 52 +251 248 4 87 76 78 72 105 76 +252 248 4 85 76 75 89 109 77 +253 248 4 88 78 79 83 116 78 +254 248 4 89 80 89 73 103 77 +134 249 4 88 76 79 66 110 74 +135 249 4 84 66 74 64 96 68 +136 249 4 83 75 75 78 104 72 +137 249 4 86 74 78 77 90 63 +138 249 4 81 73 72 69 98 62 +139 249 4 80 70 67 91 108 68 +140 249 4 90 73 75 88 105 67 +141 249 4 86 69 65 77 84 50 +251 249 4 84 73 71 95 93 61 +252 249 4 76 61 49 107 84 41 +253 249 4 85 75 74 97 125 74 +254 249 4 83 78 85 87 133 83 +251 250 4 90 81 88 85 126 85 +252 250 4 82 70 65 90 77 47 +253 250 4 90 78 79 84 108 71 +254 250 4 85 79 84 90 134 86 +252 251 4 86 80 82 86 116 82 +253 251 4 84 78 77 98 112 73 +254 251 4 83 75 76 111 121 69 +378 253 6 74 59 55 60 100 61 +377 254 6 75 61 62 68 108 61 +378 254 6 74 59 57 49 71 48 +379 254 6 69 54 45 14 11 12 +376 255 6 70 55 49 66 78 44 +377 255 6 75 61 62 68 108 61 +378 255 6 74 60 57 42 82 53 +379 255 6 72 54 46 16 18 16 +376 256 6 76 61 59 68 106 62 +377 256 6 74 59 52 30 53 36 +378 256 6 69 54 44 14 6 7 +376 257 6 76 61 59 65 93 56 +377 257 6 73 57 52 23 44 30 +132 274 4 72 58 59 62 94 59 +132 275 4 74 58 58 64 97 58 +133 275 4 74 63 65 72 114 64 +134 275 4 74 63 65 72 114 64 +135 275 4 75 58 60 59 82 52 +136 275 4 73 55 51 54 49 31 +137 275 4 64 43 34 23 16 14 +132 276 4 72 57 54 60 97 56 +133 276 4 75 65 68 77 123 70 +134 276 4 73 53 55 49 61 37 +135 276 4 61 40 30 12 10 11 +136 276 4 64 42 34 19 24 20 +137 276 4 68 47 42 42 63 37 +132 277 4 71 55 51 61 91 52 +133 277 4 74 63 61 80 114 63 +134 277 4 74 59 55 67 74 41 +135 277 4 69 50 40 40 35 24 +136 277 4 64 44 35 18 41 30 +137 277 4 71 54 52 53 96 52 +132 278 4 71 56 50 65 75 44 +133 278 4 73 60 58 75 99 54 +134 278 4 79 64 64 79 122 69 +135 278 4 77 63 59 75 109 61 +136 278 4 70 54 46 43 57 37 +137 278 4 76 62 62 69 95 55 +132 279 4 73 58 54 63 85 52 +133 279 4 73 57 56 66 94 55 +134 279 4 76 61 61 71 104 62 +135 279 4 77 63 67 73 109 62 +136 279 4 76 62 60 68 106 63 +137 279 4 75 63 59 82 116 66 +360 290 5 68 48 46 67 109 60 +361 290 5 73 56 59 64 129 79 +362 290 5 78 60 70 66 130 82 +363 290 5 78 62 65 64 120 71 +364 290 5 76 60 61 66 110 68 +365 290 5 75 57 61 64 116 70 +366 290 5 76 63 67 63 124 75 +367 290 5 78 60 63 59 118 74 +368 290 5 76 59 68 62 125 77 +369 290 5 76 60 64 63 117 73 +370 290 5 75 60 63 66 121 75 +371 290 5 72 58 57 68 105 64 +360 291 5 85 72 82 71 127 86 +361 291 5 88 75 84 69 130 87 +362 291 5 78 62 72 65 137 86 +363 291 5 80 64 68 64 124 78 +364 291 5 72 57 58 67 110 65 +365 291 5 77 60 68 63 124 78 +366 291 5 77 60 65 60 125 80 +367 291 5 78 63 66 61 123 74 +368 291 5 75 60 64 62 127 77 +369 291 5 75 62 67 61 126 79 +370 291 5 74 60 61 68 117 70 +371 291 5 72 56 50 73 96 52 +361 292 5 80 62 70 64 127 82 +362 292 5 77 62 66 64 119 75 +363 292 5 78 61 67 63 121 75 +364 292 5 74 59 65 63 117 73 +365 292 5 78 62 69 63 123 77 +366 292 5 76 60 65 62 122 76 +367 292 5 78 62 70 63 132 79 +368 292 5 75 60 69 64 127 79 +369 292 5 77 63 71 61 130 85 +370 292 5 74 59 56 64 102 61 +371 292 5 70 53 47 66 90 45 +361 293 5 73 58 62 64 119 82 +362 293 5 74 60 64 65 119 74 +363 293 5 77 59 65 63 124 75 +364 293 5 79 62 66 63 123 77 +365 293 5 77 60 68 64 125 80 +366 293 5 77 62 70 63 130 80 +367 293 5 80 62 75 63 133 85 +368 293 5 77 61 70 63 128 82 +369 293 5 74 55 54 59 90 54 +370 293 5 73 57 52 60 89 51 +371 293 5 76 57 62 63 120 73 +361 294 5 69 54 53 61 96 62 +362 294 5 76 60 63 67 114 69 +363 294 5 76 61 66 63 123 74 +364 294 5 79 62 70 65 131 81 +365 294 5 77 60 66 63 122 76 +366 294 5 75 61 66 62 124 76 +367 294 5 77 61 67 61 120 70 +368 294 5 77 59 66 63 116 71 +369 294 5 73 56 53 63 92 51 +370 294 5 76 58 60 63 112 67 +371 294 5 79 60 68 63 129 80 +361 295 5 73 58 59 61 85 51 +362 295 5 74 58 58 70 103 58 +363 295 5 77 61 63 65 117 72 +364 295 5 79 63 72 64 132 83 +365 295 5 76 59 63 61 122 73 +366 295 5 73 58 60 60 109 65 +367 295 5 76 59 55 61 96 56 +368 295 5 76 56 58 60 98 60 +369 295 5 71 57 54 67 92 52 +370 295 5 74 56 60 64 108 63 +371 295 5 77 57 61 60 108 66 +361 296 5 76 58 63 69 104 60 +362 296 5 79 63 67 61 127 80 +363 296 5 75 58 67 59 122 78 +364 296 5 75 56 59 59 105 62 +365 296 5 73 57 55 61 88 51 +366 296 5 71 58 55 68 99 56 +367 296 5 74 56 53 61 87 51 +368 296 5 71 56 55 66 90 53 +369 296 5 73 55 54 64 92 53 +370 296 5 72 54 50 63 84 51 +371 296 5 70 57 49 68 89 50 +361 297 5 74 57 64 67 113 67 +362 297 5 76 63 68 61 126 82 +363 297 5 76 59 65 58 115 71 +364 297 5 74 59 59 60 99 61 +365 297 5 73 59 54 67 99 55 +366 297 5 72 56 54 72 107 57 +367 297 5 73 59 55 69 100 55 +368 297 5 73 59 54 67 97 56 +369 297 5 73 58 53 69 93 54 +370 297 5 73 56 52 72 85 48 +371 297 5 72 58 54 70 94 52 +361 298 5 78 61 68 60 116 74 +362 298 5 77 60 61 60 111 69 +363 298 5 74 59 62 64 110 64 +364 298 5 76 60 65 63 110 68 +365 298 5 71 58 54 65 106 62 +366 298 5 71 54 54 65 95 52 +367 298 5 71 55 51 71 101 55 +368 298 5 73 57 51 66 96 55 +369 298 5 72 57 53 67 98 57 +370 298 5 75 59 59 68 105 60 +371 298 5 76 60 64 63 115 69 +362 299 5 75 58 64 60 112 72 +363 299 5 75 57 59 62 112 67 +364 299 5 72 55 57 65 101 60 +365 299 5 71 56 51 66 91 52 +366 299 5 72 55 52 65 94 55 +367 299 5 71 57 50 65 95 53 +368 299 5 71 57 50 65 95 53 +369 299 5 72 55 56 66 102 59 +370 299 5 76 60 63 60 124 77 +371 299 5 81 65 70 53 130 85 +362 300 5 74 58 64 59 115 74 +363 300 5 74 57 59 60 113 70 +364 300 5 74 59 58 64 112 66 +365 300 5 74 59 61 65 106 63 +366 300 5 76 58 56 65 105 61 +367 300 5 72 56 54 66 103 60 +368 300 5 75 57 58 61 111 65 +369 300 5 76 59 65 55 117 79 +370 300 5 84 72 81 56 130 94 +371 300 5 85 72 82 59 128 96 +362 301 5 74 57 65 60 118 74 +363 301 5 73 57 59 63 107 64 +364 301 5 76 58 60 64 118 71 +365 301 5 77 60 65 66 123 75 +366 301 5 73 56 57 62 106 63 +367 301 5 75 59 59 62 111 67 +368 301 5 71 56 57 58 104 63 +369 301 5 81 64 69 56 106 77 +370 301 5 89 75 84 57 118 95 +371 301 5 77 66 68 59 112 73 +362 302 5 75 58 62 62 116 70 +363 302 5 75 58 56 68 107 61 +364 302 5 76 60 65 67 118 72 +365 302 5 76 59 65 66 121 76 +366 302 5 73 56 57 62 106 63 +367 302 5 70 56 58 59 93 54 +368 302 5 75 63 62 57 102 69 +369 302 5 86 76 86 59 117 94 +370 302 5 83 70 80 59 113 84 +371 302 5 73 57 58 59 100 58 +363 303 5 72 56 52 68 99 54 +364 303 5 74 58 64 68 115 70 +365 303 5 74 61 59 66 109 66 +366 303 5 71 58 60 60 97 59 +367 303 5 69 59 59 57 92 53 +368 303 5 83 71 79 59 115 83 +369 303 5 87 74 84 61 124 94 +370 303 5 78 59 65 58 106 64 +371 303 5 73 54 56 57 92 58 +345 307 7 72 59 50 66 73 41 +346 307 7 83 71 70 70 88 58 +347 307 7 112 103 117 65 132 115 +348 307 7 125 118 135 65 138 133 +349 307 7 125 112 129 64 126 118 +350 307 7 121 108 122 59 124 117 +351 307 7 125 113 126 62 131 129 +345 308 7 72 60 47 69 82 46 +346 308 7 79 66 61 77 85 52 +347 308 7 116 105 115 61 112 102 +348 308 7 123 113 126 65 127 125 +349 308 7 125 113 126 63 116 114 +350 308 7 118 108 121 63 107 103 +351 308 7 132 125 148 71 130 124 +198 309 5 69 53 54 62 82 49 +199 309 5 72 54 57 56 94 58 +200 309 5 72 56 57 65 98 60 +201 309 5 74 59 60 70 107 65 +202 309 5 75 59 60 68 116 70 +203 309 5 71 59 54 69 112 68 +204 309 5 74 58 63 62 101 63 +205 309 5 77 59 68 63 111 68 +206 309 5 76 56 62 57 117 71 +207 309 5 73 58 59 61 118 71 +208 309 5 75 61 67 62 127 82 +209 309 5 80 65 70 63 122 84 +345 309 7 74 58 52 72 83 47 +346 309 7 92 79 84 64 95 72 +347 309 7 124 108 124 60 124 117 +348 309 7 138 123 135 64 142 137 +349 309 7 138 123 135 64 142 137 +350 309 7 146 135 148 71 145 139 +351 309 7 143 132 150 73 142 145 +198 310 5 68 51 50 60 73 42 +199 310 5 69 53 50 63 74 44 +200 310 5 71 56 53 66 86 49 +201 310 5 74 58 57 71 104 62 +202 310 5 74 57 57 69 106 65 +203 310 5 71 57 53 66 96 55 +204 310 5 75 60 68 64 112 71 +205 310 5 77 63 68 63 120 75 +206 310 5 71 53 49 53 80 48 +207 310 5 71 54 54 61 94 57 +208 310 5 74 58 62 65 110 69 +209 310 5 78 60 66 64 109 70 +345 310 7 72 56 47 70 74 41 +346 310 7 79 68 68 73 96 58 +347 310 7 113 101 113 60 117 113 +348 310 7 149 137 151 70 165 159 +349 310 7 170 157 176 80 182 183 +350 310 7 144 132 151 72 150 162 +351 310 7 147 138 164 79 145 145 +199 311 5 71 55 56 63 85 49 +200 311 5 73 56 56 65 85 51 +201 311 5 74 58 58 70 100 60 +202 311 5 73 57 56 68 100 58 +203 311 5 73 59 59 71 102 56 +204 311 5 77 62 68 68 121 75 +205 311 5 75 55 57 53 98 62 +206 311 5 69 52 44 52 60 36 +207 311 5 71 53 49 61 76 43 +208 311 5 74 61 64 68 120 72 +209 311 5 76 62 65 66 109 67 +345 311 7 68 52 43 62 59 35 +346 311 7 72 58 53 64 75 43 +347 311 7 97 87 102 62 111 89 +348 311 7 132 125 148 71 151 143 +349 311 7 151 140 166 77 161 161 +350 311 7 139 132 155 75 139 138 +351 311 7 153 143 170 82 152 150 +199 312 5 71 56 56 58 91 54 +200 312 5 71 56 53 60 85 54 +201 312 5 71 55 53 64 92 53 +202 312 5 73 58 58 70 98 55 +203 312 5 73 57 56 70 109 62 +204 312 5 74 56 59 57 108 69 +205 312 5 71 53 51 50 72 44 +206 312 5 70 52 46 55 63 38 +207 312 5 71 53 47 58 73 43 +208 312 5 75 59 61 65 117 69 +209 312 5 75 62 67 65 125 78 +345 312 7 69 50 43 58 48 30 +346 312 7 72 55 45 64 56 32 +347 312 7 80 64 70 65 94 54 +348 312 7 102 95 111 69 122 103 +349 312 7 123 114 131 69 130 123 +350 312 7 129 117 130 63 119 113 +351 312 7 128 115 130 64 126 121 +199 313 5 71 57 51 64 79 47 +200 313 5 71 58 55 65 87 51 +201 313 5 75 60 60 68 99 58 +202 313 5 71 57 55 66 94 54 +203 313 5 70 56 56 64 99 58 +204 313 5 71 51 49 49 73 47 +205 313 5 70 52 48 58 65 37 +206 313 5 70 53 48 58 70 40 +207 313 5 67 52 46 54 62 38 +208 313 5 72 56 53 61 95 55 +209 313 5 74 59 60 66 119 71 +345 313 7 66 49 42 57 48 27 +346 313 7 72 55 47 69 72 41 +347 313 7 66 54 45 66 64 32 +348 313 7 82 71 79 71 89 59 +349 313 7 117 106 114 64 111 108 +350 313 7 117 104 109 60 104 100 +351 313 7 104 89 95 58 84 70 +199 314 5 73 58 56 64 86 51 +200 314 5 74 59 59 61 96 61 +201 314 5 75 59 63 61 105 65 +202 314 5 72 56 53 54 82 48 +203 314 5 68 52 49 52 60 37 +204 314 5 69 54 46 59 64 37 +205 314 5 67 51 46 58 66 36 +206 314 5 69 51 44 58 62 35 +207 314 5 69 53 46 61 65 37 +208 314 5 72 57 54 62 94 53 +209 314 5 71 54 51 54 92 56 +199 315 5 72 59 59 62 98 59 +200 315 5 77 60 65 60 112 70 +201 315 5 77 59 69 58 111 69 +202 315 5 74 57 59 54 85 51 +203 315 5 73 54 54 56 80 48 +204 315 5 68 56 47 61 70 40 +205 315 5 67 53 44 62 64 35 +206 315 5 70 51 45 62 70 37 +207 315 5 70 50 45 62 69 38 +208 315 5 68 56 50 64 74 42 +209 315 5 71 53 49 60 74 44 +199 316 5 76 63 70 67 116 69 +200 316 5 80 63 76 61 126 76 +201 316 5 77 59 69 58 111 69 +202 316 5 77 61 70 60 112 70 +203 316 5 74 57 61 61 102 61 +204 316 5 69 54 48 62 79 44 +205 316 5 68 51 42 59 62 34 +206 316 5 67 52 43 61 60 33 +207 316 5 69 53 43 65 65 35 +208 316 5 69 52 47 63 66 37 +209 316 5 70 53 47 64 71 40 +199 317 5 79 64 75 68 130 83 +200 317 5 77 63 70 60 121 74 +201 317 5 77 62 72 61 118 73 +202 317 5 78 62 68 64 120 74 +203 317 5 73 58 62 63 105 63 +204 317 5 72 54 52 61 79 48 +205 317 5 69 50 43 59 62 35 +206 317 5 66 52 43 63 63 36 +207 317 5 67 52 43 65 68 38 +208 317 5 70 52 43 67 69 38 +209 317 5 69 54 44 67 71 38 +240 317 3 75 67 72 89 101 64 +241 317 3 77 70 78 89 109 67 +242 317 3 88 84 101 85 136 102 +243 317 3 90 81 89 94 133 105 +244 317 3 86 80 90 94 134 98 +245 317 3 78 74 74 106 118 77 +246 317 3 91 84 98 93 135 101 +247 317 3 86 80 89 89 120 85 +248 317 3 80 74 75 91 109 73 +274 317 3 73 63 56 105 100 51 +275 317 3 74 63 51 113 98 49 +276 317 3 74 63 50 117 100 49 +277 317 3 74 66 54 116 102 54 +278 317 3 75 66 53 110 103 51 +279 317 3 72 63 56 107 96 46 +280 317 3 74 64 56 110 98 49 +281 317 3 78 71 65 99 121 66 +282 317 3 80 71 66 99 122 69 +283 317 3 80 68 69 94 127 76 +284 317 3 80 73 69 103 123 68 +285 317 3 81 72 69 94 126 73 +286 317 3 80 75 77 84 131 79 +287 317 3 81 68 70 86 113 71 +288 317 3 76 65 63 98 108 70 +289 317 3 88 75 83 94 138 90 +199 318 5 75 58 65 60 119 72 +200 318 5 73 59 61 60 107 69 +201 318 5 74 61 66 64 115 70 +202 318 5 75 58 62 59 107 64 +203 318 5 75 61 63 62 104 62 +204 318 5 75 58 58 60 96 57 +205 318 5 73 53 52 59 79 46 +206 318 5 71 54 52 65 77 43 +207 318 5 70 54 52 67 80 47 +208 318 5 68 52 42 71 75 44 +209 318 5 66 54 44 68 73 37 +240 318 3 83 77 87 90 121 82 +241 318 3 81 73 75 92 117 75 +242 318 3 79 72 73 96 108 67 +243 318 3 77 71 74 100 109 67 +244 318 3 78 71 79 96 128 85 +245 318 3 81 75 83 94 120 77 +246 318 3 83 77 80 94 115 75 +247 318 3 95 93 108 81 130 106 +248 318 3 85 80 84 92 124 91 +249 318 3 72 60 52 102 96 47 +274 318 3 72 63 53 110 99 50 +275 318 3 73 63 52 112 98 48 +276 318 3 74 63 54 114 103 53 +277 318 3 76 66 56 116 107 57 +278 318 3 75 67 55 109 108 59 +279 318 3 72 62 53 106 98 53 +280 318 3 74 64 55 115 96 45 +281 318 3 74 69 61 114 111 57 +282 318 3 77 68 57 110 107 59 +283 318 3 78 69 66 102 123 66 +284 318 3 78 71 64 98 120 67 +285 318 3 78 68 68 94 122 73 +286 318 3 79 70 64 98 118 65 +287 318 3 74 62 55 82 101 55 +288 318 3 105 96 110 79 139 116 +289 318 3 88 75 83 94 138 90 +240 319 3 91 89 103 82 137 108 +241 319 3 93 89 106 79 136 106 +242 319 3 91 84 100 85 128 98 +243 319 3 88 84 105 85 133 102 +244 319 3 90 86 111 81 147 110 +245 319 3 88 83 92 88 133 94 +246 319 3 94 91 105 83 136 109 +247 319 3 83 77 80 96 120 88 +248 319 3 71 62 51 101 103 61 +249 319 3 76 64 56 97 102 58 +275 319 3 73 61 50 108 100 52 +276 319 3 74 64 58 106 108 56 +277 319 3 76 64 55 111 112 55 +278 319 3 74 61 53 95 100 53 +279 319 3 70 57 47 80 84 47 +280 319 3 72 64 52 90 90 47 +281 319 3 74 66 58 104 106 53 +282 319 3 75 63 51 101 99 53 +283 319 3 77 67 58 110 105 51 +284 319 3 73 66 53 104 105 54 +285 319 3 73 63 58 107 96 49 +286 319 3 75 65 49 115 95 45 +287 319 3 69 57 39 101 83 34 +288 319 3 127 118 141 81 164 136 +289 319 3 109 99 113 89 152 118 +240 320 3 78 69 65 95 108 67 +241 320 3 79 75 78 90 116 81 +242 320 3 85 77 88 91 123 90 +243 320 3 81 74 81 97 122 86 +244 320 3 74 66 64 108 114 76 +245 320 3 88 85 96 89 137 105 +246 320 3 77 68 65 103 109 74 +247 320 3 75 61 54 104 95 48 +248 320 3 74 64 58 95 94 49 +249 320 3 75 63 57 100 92 51 +275 320 3 72 60 51 105 91 46 +276 320 3 74 66 60 96 113 61 +277 320 3 76 65 60 96 114 61 +278 320 3 74 59 57 76 98 54 +279 320 3 72 59 55 70 80 47 +280 320 3 74 64 55 79 92 56 +281 320 3 76 63 55 95 95 52 +282 320 3 74 64 55 103 108 60 +283 320 3 75 63 54 104 101 52 +284 320 3 74 67 51 112 107 56 +285 320 3 74 63 53 112 103 51 +286 320 3 71 63 48 116 99 49 +287 320 3 70 57 36 118 85 36 +288 320 3 107 98 114 94 145 117 +289 320 3 137 127 149 93 185 154 +348 320 7 116 111 127 70 125 110 +349 320 7 125 118 135 70 120 113 +350 320 7 137 132 154 74 137 131 +240 321 3 90 88 96 79 112 83 +241 321 3 86 77 83 87 104 69 +242 321 3 82 71 73 95 105 59 +243 321 3 75 68 65 104 101 52 +244 321 3 76 65 59 111 87 41 +245 321 3 73 62 55 114 104 59 +246 321 3 74 67 59 103 89 42 +247 321 3 78 69 65 89 96 50 +248 321 3 77 70 68 91 107 68 +249 321 3 77 69 62 99 95 58 +275 321 3 75 65 60 91 116 63 +276 321 3 75 65 60 91 116 63 +277 321 3 77 66 65 83 120 66 +278 321 3 77 62 61 81 103 59 +279 321 3 75 67 63 92 106 60 +280 321 3 77 69 68 91 116 66 +281 321 3 77 63 58 92 96 54 +282 321 3 78 69 60 105 109 56 +283 321 3 75 64 53 105 110 56 +284 321 3 76 67 52 113 110 57 +285 321 3 75 66 56 112 110 55 +286 321 3 77 68 58 114 107 57 +287 321 3 75 68 53 118 103 50 +288 321 3 81 72 69 105 111 65 +289 321 3 124 116 131 97 177 144 +348 321 7 130 119 138 67 127 122 +349 321 7 132 116 128 65 119 117 +350 321 7 130 120 137 63 122 119 +240 322 3 82 77 78 88 117 91 +241 322 3 86 75 83 89 120 92 +242 322 3 89 78 89 88 124 94 +243 322 3 82 78 80 88 113 80 +244 322 3 73 61 54 85 86 49 +245 322 3 79 69 61 107 89 46 +246 322 3 81 76 82 92 113 76 +247 322 3 90 87 102 80 129 96 +248 322 3 89 83 94 78 123 95 +249 322 3 81 74 80 89 109 77 +275 322 3 72 63 55 89 103 56 +276 322 3 65 53 44 94 91 45 +277 322 3 86 74 74 97 113 68 +278 322 3 109 105 115 105 131 95 +279 322 3 97 93 102 97 128 85 +280 322 3 77 66 64 82 108 62 +281 322 3 90 79 81 89 121 89 +282 322 3 90 84 90 95 135 94 +283 322 3 83 73 69 101 114 62 +284 322 3 83 75 73 99 117 74 +285 322 3 87 79 76 100 127 85 +286 322 3 85 77 77 99 120 79 +287 322 3 80 74 66 100 119 78 +288 322 3 80 74 66 100 119 78 +289 322 3 82 76 71 101 116 68 +348 322 7 116 101 112 54 99 97 +349 322 7 124 110 123 59 113 109 +350 322 7 109 93 95 54 85 87 +240 323 3 85 75 83 85 107 70 +241 323 3 89 81 93 80 120 93 +242 323 3 99 97 118 77 136 121 +243 323 3 96 89 103 75 110 93 +244 323 3 75 59 57 68 72 45 +245 323 3 74 60 58 87 87 52 +246 323 3 87 84 98 83 128 98 +247 323 3 97 97 118 74 144 125 +248 323 3 90 86 95 78 122 99 +249 323 3 79 69 72 97 101 65 +250 323 3 81 74 81 94 123 88 +276 323 3 76 65 60 94 78 30 +277 323 3 95 89 92 93 126 91 +278 323 3 154 156 182 109 215 199 +279 323 3 132 129 145 114 205 174 +280 323 3 79 69 73 83 120 80 +281 323 3 95 88 99 82 152 109 +282 323 3 85 73 81 88 139 88 +283 323 3 89 84 91 88 137 96 +284 323 3 90 79 87 87 146 97 +285 323 3 88 80 84 85 144 94 +286 323 3 87 76 82 82 135 87 +287 323 3 86 79 87 84 131 88 +288 323 3 89 81 87 92 127 87 +289 323 3 79 72 67 103 108 61 +240 324 3 91 88 108 73 131 109 +241 324 3 101 102 130 73 140 122 +242 324 3 102 95 113 68 115 100 +243 324 3 76 61 60 66 73 46 +244 324 3 72 59 55 72 85 53 +245 324 3 88 86 104 77 127 97 +246 324 3 99 98 121 74 136 118 +247 324 3 90 83 89 84 113 88 +248 324 3 90 83 89 84 113 88 +249 324 3 73 62 55 109 91 54 +250 324 3 69 56 51 119 86 43 +276 324 3 76 65 60 94 78 30 +277 324 3 90 84 89 85 113 80 +278 324 3 130 130 147 101 209 196 +279 324 3 120 119 129 113 209 189 +280 324 3 79 70 74 77 136 86 +281 324 3 89 78 86 78 178 115 +282 324 3 86 73 77 77 151 92 +283 324 3 87 78 80 87 155 102 +284 324 3 83 72 76 86 134 86 +285 324 3 85 72 75 79 130 82 +286 324 3 82 70 75 84 128 80 +287 324 3 85 74 78 86 144 93 +288 324 3 83 71 71 96 132 86 +289 324 3 88 78 78 99 126 84 +240 325 3 90 86 116 75 134 108 +241 325 3 95 98 127 73 135 116 +242 325 3 98 92 104 70 114 95 +243 325 3 73 59 54 73 77 47 +244 325 3 77 68 71 76 98 66 +245 325 3 92 90 110 71 133 105 +246 325 3 96 94 116 76 130 105 +247 325 3 87 78 80 84 104 76 +248 325 3 81 71 72 86 103 70 +249 325 3 77 64 62 106 97 60 +250 325 3 72 59 44 122 86 42 +276 325 3 104 97 101 88 115 85 +277 325 3 109 103 109 91 120 83 +278 325 3 106 102 117 101 154 122 +279 325 3 94 88 87 97 156 121 +280 325 3 83 68 66 69 128 82 +281 325 3 79 65 61 55 95 59 +282 325 3 76 64 58 60 74 47 +283 325 3 80 69 70 84 133 83 +284 325 3 78 65 63 81 124 74 +285 325 3 81 66 64 80 125 75 +286 325 3 81 70 69 88 122 74 +287 325 3 82 72 73 89 120 71 +288 325 3 80 68 67 100 114 67 +289 325 3 78 62 57 107 108 65 +240 326 3 92 87 113 73 129 104 +241 326 3 97 96 124 71 131 116 +242 326 3 92 83 94 67 103 83 +243 326 3 72 56 50 69 69 40 +244 326 3 74 63 63 78 92 62 +245 326 3 94 92 109 74 135 109 +246 326 3 83 77 81 91 113 81 +247 326 3 73 61 52 102 89 51 +248 326 3 83 72 78 83 105 74 +249 326 3 92 85 99 73 119 93 +250 326 3 89 83 91 82 121 89 +276 326 3 133 129 145 87 160 140 +277 326 3 131 125 144 85 165 147 +278 326 3 104 93 102 91 143 118 +279 326 3 87 74 71 78 106 72 +280 326 3 74 58 50 35 50 28 +281 326 3 71 54 47 20 25 20 +282 326 3 75 65 59 61 57 35 +283 326 3 76 63 58 84 98 56 +284 326 3 76 61 59 91 106 60 +285 326 3 78 67 62 93 113 66 +286 326 3 81 72 74 88 130 80 +287 326 3 83 73 77 84 137 83 +288 326 3 82 72 75 87 125 72 +289 326 3 80 66 63 102 118 66 +389 326 1 116 107 128 68 151 128 +390 326 1 104 91 101 62 111 85 +391 326 1 104 91 101 62 111 85 +392 326 1 119 104 112 59 107 92 +393 326 1 113 95 110 52 87 80 +394 326 1 95 76 82 47 65 53 +395 326 1 86 70 70 67 83 53 +396 326 1 84 70 75 73 100 68 +397 326 1 81 69 68 63 82 53 +398 326 1 72 58 51 73 70 42 +399 326 1 69 56 46 84 77 35 +240 327 3 95 87 107 71 120 102 +241 327 3 102 97 119 72 127 109 +242 327 3 86 75 84 61 98 79 +243 327 3 68 54 47 59 68 39 +244 327 3 68 56 48 83 77 40 +245 327 3 84 78 87 85 112 83 +246 327 3 78 70 65 96 101 61 +247 327 3 69 54 38 115 85 39 +248 327 3 69 55 40 120 84 39 +249 327 3 77 68 63 105 98 58 +250 327 3 82 74 76 92 106 73 +277 327 3 122 115 122 97 156 133 +278 327 3 99 92 95 96 142 113 +279 327 3 81 71 65 69 93 65 +280 327 3 70 53 48 28 15 11 +281 327 3 71 55 49 34 12 9 +282 327 3 75 65 59 61 57 35 +283 327 3 78 66 61 91 107 58 +284 327 3 74 62 55 98 103 53 +285 327 3 76 66 59 95 111 58 +286 327 3 81 68 66 94 120 65 +287 327 3 80 69 65 87 115 71 +288 327 3 82 73 77 83 123 83 +289 327 3 80 70 65 94 114 64 +380 327 1 157 147 171 93 161 142 +381 327 1 119 100 109 57 94 95 +382 327 1 97 74 77 42 82 78 +383 327 1 111 96 103 57 88 84 +384 327 1 108 89 100 54 86 78 +385 327 1 105 84 91 47 77 73 +386 327 1 116 95 104 58 81 79 +387 327 1 147 137 161 89 165 145 +388 327 1 140 137 163 86 188 160 +389 327 1 106 95 109 57 110 95 +390 327 1 78 58 63 46 80 57 +391 327 1 93 77 78 60 83 56 +392 327 1 97 84 95 66 96 75 +393 327 1 91 74 78 63 89 68 +394 327 1 88 74 76 65 80 58 +395 327 1 85 72 76 65 99 71 +396 327 1 81 66 65 75 88 57 +397 327 1 73 63 56 80 88 49 +398 327 1 69 54 44 85 72 37 +399 327 1 69 56 41 98 80 39 +240 328 3 92 83 100 70 114 92 +241 328 3 104 99 122 71 125 108 +242 328 3 86 75 85 55 88 71 +243 328 3 67 52 44 58 65 38 +244 328 3 73 62 53 88 79 39 +245 328 3 84 77 81 88 114 82 +246 328 3 90 86 99 78 128 100 +247 328 3 82 74 82 89 106 69 +248 328 3 73 61 51 114 86 41 +249 328 3 67 54 32 129 83 39 +250 328 3 67 53 37 126 85 39 +277 328 3 85 76 72 98 126 86 +278 328 3 81 70 65 91 113 67 +279 328 3 79 66 65 64 79 51 +280 328 3 77 64 56 52 57 38 +281 328 3 75 62 58 76 80 43 +282 328 3 79 68 63 91 118 69 +283 328 3 73 65 59 95 103 50 +284 328 3 82 69 63 94 97 50 +285 328 3 82 69 63 94 97 50 +286 328 3 87 78 82 93 113 70 +287 328 3 90 77 80 82 114 80 +288 328 3 89 82 87 74 102 81 +289 328 3 82 72 71 100 118 75 +380 328 1 119 99 107 63 109 105 +381 328 1 104 81 85 46 76 72 +382 328 1 101 83 87 46 83 77 +383 328 1 98 81 85 49 87 77 +384 328 1 105 85 94 51 88 82 +385 328 1 107 87 96 49 90 86 +386 328 1 109 90 96 48 87 80 +387 328 1 110 90 101 55 94 89 +388 328 1 118 107 124 70 112 97 +389 328 1 135 131 152 79 111 88 +390 328 1 107 91 101 58 70 60 +391 328 1 100 86 94 59 73 62 +392 328 1 89 70 72 55 79 65 +393 328 1 88 74 73 71 91 64 +394 328 1 94 80 85 65 88 60 +395 328 1 90 76 83 67 99 70 +396 328 1 80 67 62 85 97 58 +397 328 1 84 77 73 86 111 74 +398 328 1 81 66 62 79 80 53 +399 328 1 74 58 49 94 82 45 +400 328 1 81 68 60 82 87 51 +240 329 3 84 75 75 75 100 76 +241 329 3 95 86 98 76 125 104 +242 329 3 79 67 69 64 73 63 +243 329 3 68 55 48 78 68 38 +244 329 3 74 62 50 101 84 46 +245 329 3 87 80 85 89 113 83 +246 329 3 91 88 108 75 129 105 +247 329 3 90 86 105 79 135 103 +248 329 3 83 75 76 94 122 81 +249 329 3 72 62 49 113 98 48 +250 329 3 71 59 44 118 92 47 +251 329 3 69 55 38 121 84 40 +380 329 1 92 74 76 62 82 74 +381 329 1 100 82 86 52 78 72 +382 329 1 101 83 90 52 84 78 +383 329 1 104 88 95 52 89 81 +384 329 1 103 86 94 55 92 86 +385 329 1 104 86 94 53 93 87 +386 329 1 107 91 99 53 92 88 +387 329 1 96 78 83 51 79 79 +388 329 1 119 107 123 70 103 82 +389 329 1 135 131 152 79 111 88 +390 329 1 139 131 158 79 128 90 +391 329 1 113 105 117 57 105 77 +392 329 1 87 64 64 44 58 54 +393 329 1 94 78 79 66 84 67 +394 329 1 98 81 89 56 86 67 +395 329 1 95 81 87 60 91 80 +396 329 1 85 75 74 78 113 69 +397 329 1 96 84 89 73 111 79 +398 329 1 93 79 81 64 98 70 +399 329 1 87 73 73 61 85 60 +400 329 1 87 71 68 68 80 60 +240 330 3 73 63 55 104 97 58 +241 330 3 71 58 46 111 85 46 +242 330 3 71 59 51 103 85 43 +243 330 3 72 59 49 107 86 43 +244 330 3 74 62 50 101 84 46 +245 330 3 75 64 55 106 98 59 +246 330 3 76 64 62 103 108 65 +247 330 3 80 70 70 99 113 70 +248 330 3 80 73 70 96 112 67 +249 330 3 78 66 56 103 97 52 +250 330 3 71 59 45 113 84 43 +251 330 3 71 62 47 118 93 46 +380 330 1 87 73 74 72 84 64 +381 330 1 94 79 85 65 83 72 +382 330 1 98 81 87 64 88 76 +383 330 1 101 84 92 55 88 84 +384 330 1 99 84 91 59 95 81 +385 330 1 101 86 92 60 97 88 +386 330 1 99 83 90 59 98 91 +387 330 1 96 81 85 59 90 80 +388 330 1 92 76 80 55 90 73 +389 330 1 144 139 165 87 112 85 +390 330 1 107 96 114 65 96 77 +391 330 1 101 88 100 62 89 71 +392 330 1 95 79 82 60 79 66 +393 330 1 99 80 83 55 77 65 +394 330 1 98 79 87 50 74 66 +395 330 1 92 75 80 57 94 71 +396 330 1 96 81 91 67 95 76 +397 330 1 96 82 92 60 82 71 +398 330 1 95 77 81 51 79 63 +399 330 1 96 80 87 45 70 56 +400 330 1 87 71 76 58 73 51 +240 331 3 71 57 42 123 85 39 +241 331 3 68 56 40 131 84 37 +242 331 3 73 61 48 102 88 44 +243 331 3 71 58 48 100 84 41 +244 331 3 68 56 35 124 82 39 +245 331 3 67 54 34 122 80 38 +246 331 3 75 65 62 99 106 61 +247 331 3 85 76 81 84 123 80 +248 331 3 80 68 63 97 104 62 +249 331 3 70 59 44 115 83 41 +250 331 3 70 58 42 122 78 37 +251 331 3 70 60 43 125 84 38 +380 331 1 97 81 84 64 75 53 +381 331 1 98 80 87 64 90 72 +382 331 1 95 77 79 66 91 70 +383 331 1 98 81 85 63 94 83 +384 331 1 97 81 87 61 90 77 +385 331 1 94 79 83 60 90 73 +386 331 1 93 75 79 61 92 75 +387 331 1 95 76 80 58 90 76 +388 331 1 93 78 82 56 88 74 +389 331 1 86 69 73 53 91 68 +390 331 1 90 72 72 58 83 67 +391 331 1 94 75 78 59 81 68 +392 331 1 100 80 83 59 83 69 +393 331 1 99 85 90 51 82 75 +394 331 1 98 80 86 64 86 70 +395 331 1 88 73 78 64 87 62 +396 331 1 92 78 81 61 103 72 +397 331 1 93 80 88 55 88 73 +398 331 1 93 72 80 46 71 58 +399 331 1 97 79 93 49 86 71 +400 331 1 92 76 82 52 72 58 +380 332 1 93 76 84 58 83 66 +381 332 1 87 71 73 55 71 49 +382 332 1 90 67 69 45 55 44 +383 332 1 93 75 79 51 76 63 +384 332 1 88 69 70 46 69 52 +385 332 1 88 67 68 44 67 52 +386 332 1 94 76 79 48 79 67 +387 332 1 94 76 79 48 79 67 +388 332 1 93 78 82 51 79 69 +389 332 1 95 80 85 58 79 69 +390 332 1 102 86 92 57 73 71 +391 332 1 100 84 93 61 81 76 +392 332 1 92 76 79 69 88 71 +393 332 1 90 76 80 67 84 69 +394 332 1 93 78 83 61 95 67 +395 332 1 88 73 78 64 87 62 +396 332 1 94 71 76 44 70 53 +397 332 1 94 75 80 45 77 64 +398 332 1 97 76 86 45 67 56 +399 332 1 95 75 85 47 70 60 +400 332 1 93 74 75 46 68 57 +380 333 1 94 75 82 52 82 71 +381 333 1 94 71 75 45 61 47 +382 333 1 89 69 71 39 56 46 +383 333 1 91 71 74 42 61 52 +384 333 1 87 65 67 40 49 42 +385 333 1 86 63 64 37 43 33 +386 333 1 89 66 67 37 53 47 +387 333 1 89 69 70 35 57 53 +388 333 1 94 81 86 57 91 66 +389 333 1 118 105 115 72 110 98 +390 333 1 108 96 102 74 103 86 +391 333 1 88 75 78 65 87 66 +392 333 1 93 80 85 62 86 68 +393 333 1 92 78 82 58 89 66 +394 333 1 97 77 83 50 68 56 +395 333 1 97 75 77 39 57 52 +396 333 1 96 74 80 41 64 53 +397 333 1 98 75 81 42 66 54 +398 333 1 97 77 82 41 62 51 +399 333 1 93 73 75 38 59 49 +400 333 1 93 73 75 38 59 49 +396 334 1 101 82 86 47 59 46 +397 334 1 92 72 76 40 58 50 +398 334 1 95 72 76 40 62 52 +399 334 1 93 72 78 40 60 48 +400 334 1 92 74 78 41 61 52 +185 346 4 80 69 69 85 110 70 +186 346 4 71 59 52 77 79 42 +185 347 4 85 71 73 76 86 58 +186 347 4 74 61 55 79 74 42 +187 347 4 75 67 61 80 95 56 +188 347 4 78 68 66 66 109 72 +184 348 4 80 70 69 71 92 59 +185 348 4 91 79 81 78 93 67 +186 348 4 76 62 57 84 77 43 +187 348 4 76 66 60 86 94 55 +188 348 4 84 72 69 81 103 71 +189 348 4 81 68 63 85 92 64 +184 349 4 74 60 55 70 81 49 +185 349 4 87 76 72 80 93 61 +186 349 4 74 63 58 81 80 45 +187 349 4 77 64 62 81 95 55 +188 349 4 81 68 64 94 102 62 +189 349 4 73 60 52 97 82 48 +184 350 4 82 71 72 80 104 64 +185 350 4 71 59 55 72 82 47 +186 350 4 75 58 55 74 87 52 +187 350 4 81 69 68 85 112 64 +188 350 4 77 63 59 83 90 48 +189 350 4 73 56 50 75 77 46 +184 351 4 80 73 73 85 101 65 +185 351 4 78 65 64 78 77 45 +186 351 4 72 60 51 79 75 43 +187 351 4 81 70 68 83 113 67 +188 351 4 79 67 67 81 107 62 +189 351 4 71 56 49 76 74 39 +184 352 4 86 82 81 92 116 77 +185 352 4 79 63 60 75 78 50 +186 352 4 75 57 53 74 70 37 +187 352 4 79 68 68 79 96 61 +188 352 4 83 71 74 81 112 72 +189 352 4 75 61 61 79 101 55 +183 353 4 84 73 70 80 103 66 +184 353 4 87 79 83 81 116 80 +185 353 4 85 71 73 78 94 64 +186 353 4 85 68 70 77 84 54 +187 353 4 89 79 79 77 88 63 +188 353 4 85 76 78 79 103 71 +189 353 4 80 71 71 84 111 68 +183 354 4 74 64 58 82 95 54 +184 354 4 82 68 69 85 100 65 +185 354 4 80 65 66 70 97 64 +186 354 4 83 70 70 68 97 68 +187 354 4 88 75 74 70 84 59 +188 354 4 82 69 63 80 81 48 +189 354 4 81 70 71 85 105 66 +183 355 4 75 63 58 77 83 48 +184 355 4 84 71 71 89 98 60 +185 355 4 73 59 57 76 85 49 +186 355 4 74 58 55 66 75 44 +187 355 4 75 58 53 70 64 38 +188 355 4 69 54 44 85 68 34 +371 358 7 101 95 111 74 118 91 +372 358 7 118 105 119 69 137 124 +373 358 7 110 105 118 70 134 120 +371 359 7 102 97 111 75 118 92 +372 359 7 106 97 108 70 120 100 +373 359 7 110 105 118 70 134 120 +374 359 7 112 107 122 73 136 120 +371 360 7 108 100 114 62 119 107 +372 360 7 104 88 94 54 95 81 +373 360 7 109 101 111 69 108 92 +372 361 7 102 85 91 53 94 86 +373 361 7 110 95 104 63 97 86 +372 362 7 105 93 103 56 102 94 +373 362 7 111 93 95 51 87 78 +295 370 5 69 56 56 58 95 56 +296 370 5 72 55 57 59 105 66 +297 370 5 74 58 61 61 113 69 +298 370 5 75 57 63 62 122 76 +299 370 5 73 57 60 59 114 67 +300 370 5 75 56 56 54 94 58 +301 370 5 72 52 54 52 85 55 +302 370 5 72 52 50 51 84 51 +303 370 5 71 53 53 56 89 55 +304 370 5 71 55 55 57 94 57 +305 370 5 70 52 52 54 84 50 +306 370 5 70 53 48 61 72 43 +295 371 5 73 56 56 58 85 51 +296 371 5 68 51 50 57 80 48 +297 371 5 75 58 61 61 110 69 +298 371 5 75 59 61 59 114 72 +299 371 5 74 59 61 58 112 66 +300 371 5 72 55 54 55 102 62 +301 371 5 71 53 51 53 86 54 +302 371 5 71 52 50 52 74 46 +303 371 5 70 52 46 51 78 46 +304 371 5 65 49 44 56 71 41 +305 371 5 66 49 42 61 59 33 +306 371 5 70 52 48 62 65 38 +295 372 5 66 52 46 56 69 41 +296 372 5 67 49 44 60 62 33 +297 372 5 70 54 49 60 79 45 +298 372 5 70 52 52 58 85 51 +299 372 5 73 57 59 56 101 62 +300 372 5 73 56 58 54 98 59 +301 372 5 68 52 50 57 75 43 +302 372 5 69 52 49 59 69 41 +303 372 5 69 50 44 54 65 37 +304 372 5 67 49 42 61 57 29 +305 372 5 68 50 44 63 62 35 +306 372 5 71 54 52 61 84 50 +399 372 5 65 49 42 60 58 30 +400 372 5 69 51 42 63 57 32 +401 372 5 68 50 40 66 59 34 +402 372 5 70 51 42 69 68 34 +403 372 5 74 54 48 66 74 44 +404 372 5 78 59 63 65 105 62 +405 372 5 81 66 71 65 111 71 +406 372 5 71 52 48 53 70 45 +407 372 5 67 51 43 66 75 43 +408 372 5 69 56 48 67 75 41 +409 372 5 71 56 47 60 61 37 +295 373 5 68 50 41 62 60 29 +296 373 5 68 50 41 62 60 29 +297 373 5 71 52 46 62 63 36 +298 373 5 69 48 41 59 58 30 +299 373 5 67 54 53 60 83 51 +300 373 5 70 53 54 56 86 52 +301 373 5 72 52 49 58 75 43 +302 373 5 72 52 50 59 79 49 +303 373 5 69 52 47 57 63 37 +304 373 5 68 52 46 60 72 39 +305 373 5 72 55 56 59 96 59 +306 373 5 73 58 60 57 100 64 +399 373 5 68 49 42 62 56 30 +400 373 5 70 51 46 66 57 30 +401 373 5 69 51 42 63 54 31 +402 373 5 67 49 39 65 59 29 +403 373 5 73 55 51 65 68 39 +404 373 5 78 60 65 68 106 63 +405 373 5 78 66 71 65 125 78 +406 373 5 66 49 45 50 62 38 +407 373 5 67 50 46 62 62 37 +408 373 5 70 55 46 73 72 40 +409 373 5 71 57 48 78 73 39 +295 374 5 67 51 45 62 64 31 +296 374 5 67 51 45 62 66 36 +297 374 5 68 49 45 62 59 30 +298 374 5 69 49 46 60 63 36 +299 374 5 71 54 49 57 74 45 +300 374 5 72 57 57 61 87 52 +301 374 5 72 55 56 60 93 56 +302 374 5 71 50 46 58 73 43 +303 374 5 67 52 44 60 66 36 +304 374 5 68 53 51 57 81 49 +305 374 5 69 51 49 57 72 45 +306 374 5 73 53 50 59 81 48 +399 374 5 68 50 41 70 59 29 +400 374 5 72 53 46 66 63 38 +401 374 5 69 50 41 57 58 33 +402 374 5 70 51 44 73 69 35 +403 374 5 75 59 57 71 86 53 +404 374 5 78 61 64 63 97 58 +405 374 5 74 57 61 59 113 69 +406 374 5 68 50 43 53 62 35 +407 374 5 67 50 46 64 55 32 +408 374 5 73 61 51 82 87 49 +295 375 5 68 50 45 60 65 36 +296 375 5 67 50 44 61 66 38 +297 375 5 70 49 45 61 69 38 +298 375 5 68 50 44 60 60 34 +299 375 5 71 51 43 58 66 38 +300 375 5 72 57 55 62 92 56 +301 375 5 70 57 59 60 100 60 +302 375 5 68 50 48 55 77 44 +303 375 5 69 50 43 60 60 33 +304 375 5 67 52 45 59 59 33 +305 375 5 68 50 45 60 54 31 +306 375 5 71 50 51 60 75 44 +399 375 5 69 50 42 67 61 33 +400 375 5 72 54 49 60 58 35 +401 375 5 70 51 43 51 48 31 +402 375 5 72 51 45 66 69 38 +403 375 5 74 58 55 62 84 51 +404 375 5 72 56 53 51 76 50 +405 375 5 69 49 43 56 74 41 +406 375 5 70 50 44 57 59 36 +407 375 5 69 53 43 66 65 36 +408 375 5 72 59 51 72 80 43 +295 376 5 68 50 46 62 64 38 +296 376 5 67 50 44 61 66 38 +297 376 5 68 51 46 61 69 39 +298 376 5 67 50 46 58 68 39 +299 376 5 69 49 43 59 60 31 +300 376 5 69 53 50 63 78 47 +301 376 5 73 54 57 58 90 58 +302 376 5 69 50 48 54 70 39 +303 376 5 69 51 45 57 65 39 +304 376 5 69 51 44 57 65 39 +305 376 5 67 48 41 59 56 33 +306 376 5 70 51 49 61 71 44 +399 376 5 68 51 38 64 57 32 +400 376 5 68 52 43 61 60 32 +401 376 5 67 52 46 61 58 35 +402 376 5 69 54 46 65 64 37 +403 376 5 71 53 50 62 78 45 +404 376 5 70 54 48 49 56 38 +405 376 5 68 48 40 59 55 31 +406 376 5 70 51 45 57 54 29 +407 376 5 68 54 44 67 71 38 +408 376 5 71 59 52 73 86 46 +295 377 5 68 50 43 62 64 34 +296 377 5 70 50 44 61 65 37 +297 377 5 67 51 42 62 65 37 +298 377 5 64 51 43 60 64 35 +299 377 5 68 51 45 64 65 37 +300 377 5 69 54 54 66 83 49 +301 377 5 74 54 56 58 90 54 +302 377 5 71 51 45 56 66 39 +303 377 5 66 50 42 60 59 33 +304 377 5 70 50 44 59 63 37 +305 377 5 67 48 41 61 56 32 +306 377 5 71 51 47 64 67 40 +400 377 5 69 52 45 66 60 32 +401 377 5 69 54 48 65 72 41 +402 377 5 69 53 49 65 74 43 +403 377 5 71 53 50 62 78 45 +404 377 5 69 50 48 57 60 34 +405 377 5 69 53 44 62 62 35 +406 377 5 72 54 46 61 63 36 +407 377 5 68 58 50 69 72 40 +408 377 5 74 60 52 73 85 49 +295 378 5 67 50 42 62 61 30 +296 378 5 69 50 44 61 63 34 +297 378 5 67 50 40 62 61 35 +298 378 5 66 51 43 64 62 32 +299 378 5 69 53 51 64 78 47 +300 378 5 73 56 61 64 108 67 +301 378 5 73 55 58 58 102 62 +302 378 5 69 52 46 56 76 44 +303 378 5 65 49 40 62 55 29 +304 378 5 70 50 42 60 61 35 +305 378 5 69 49 43 62 60 35 +306 378 5 69 50 45 62 67 37 +400 378 5 74 59 53 69 71 44 +401 378 5 72 55 47 61 71 45 +402 378 5 69 51 45 56 61 36 +403 378 5 72 54 46 62 65 38 +404 378 5 76 58 53 64 67 41 +405 378 5 79 68 62 64 78 52 +406 378 5 72 59 54 69 78 49 +407 378 5 71 58 49 72 74 41 +408 378 5 76 61 57 63 80 47 +295 379 5 68 49 43 64 62 31 +296 379 5 69 50 42 64 64 37 +297 379 5 67 49 46 60 65 36 +298 379 5 69 52 48 62 81 46 +299 379 5 71 55 57 62 91 55 +300 379 5 75 55 62 58 99 61 +301 379 5 72 55 54 55 89 52 +302 379 5 69 52 46 56 76 44 +303 379 5 67 49 42 60 61 32 +304 379 5 67 47 40 62 54 32 +305 379 5 68 51 44 64 58 34 +306 379 5 70 51 47 66 71 38 +400 379 5 68 56 43 66 70 40 +401 379 5 68 52 44 71 68 39 +402 379 5 70 52 43 65 62 34 +403 379 5 68 51 46 58 57 34 +404 379 5 72 54 44 61 59 35 +405 379 5 72 57 50 63 76 48 +406 379 5 75 58 54 67 83 53 +407 379 5 76 61 55 74 83 46 +408 379 5 76 59 57 68 82 49 +295 380 5 68 52 47 58 76 42 +296 380 5 69 50 51 59 79 43 +297 380 5 68 53 52 58 85 51 +298 380 5 71 56 56 56 95 58 +299 380 5 73 53 55 56 91 54 +300 380 5 70 52 51 56 77 44 +301 380 5 68 51 46 56 63 36 +302 380 5 69 50 43 59 64 36 +303 380 5 66 49 41 63 55 28 +304 380 5 66 49 41 63 55 28 +305 380 5 67 51 44 67 64 38 +306 380 5 70 55 51 65 90 50 +400 380 5 69 51 43 61 65 34 +401 380 5 66 49 39 65 63 32 +402 380 5 66 51 41 73 73 38 +403 380 5 69 53 45 64 60 37 +404 380 5 70 52 50 58 64 36 +405 380 5 74 59 51 61 70 39 +406 380 5 77 64 63 74 89 55 +407 380 5 79 69 64 90 106 60 +408 380 5 81 68 65 84 105 68 +295 381 5 71 51 46 57 65 38 +296 381 5 70 52 49 57 78 45 +297 381 5 67 52 49 56 82 50 +298 381 5 68 53 51 56 80 47 +299 381 5 70 52 49 57 75 42 +300 381 5 68 49 45 57 68 40 +301 381 5 67 48 42 57 60 34 +302 381 5 66 49 42 60 55 30 +303 381 5 66 51 41 65 57 29 +304 381 5 69 53 47 67 75 44 +305 381 5 73 57 56 61 96 59 +306 381 5 74 55 61 55 94 57 +400 381 5 70 50 42 58 66 38 +401 381 5 67 49 41 59 58 31 +402 381 5 67 51 44 68 72 37 +403 381 5 71 56 49 76 82 47 +404 381 5 75 59 54 69 89 52 +405 381 5 73 56 52 59 78 46 +406 381 5 70 56 52 63 75 46 +407 381 5 73 57 53 77 87 47 +408 381 5 80 64 60 80 85 55 +116 382 5 69 51 48 60 72 40 +117 382 5 69 51 42 58 59 35 +118 382 5 69 52 42 63 58 31 +119 382 5 67 50 45 65 58 29 +120 382 5 67 49 44 59 59 31 +121 382 5 67 51 45 60 59 32 +122 382 5 70 52 45 58 63 38 +123 382 5 69 50 43 57 59 31 +124 382 5 70 51 46 62 69 39 +125 382 5 67 51 41 59 75 45 +126 382 5 70 54 47 54 64 39 +127 382 5 70 54 48 50 70 43 +400 382 5 69 52 45 56 72 40 +401 382 5 69 52 45 59 78 42 +402 382 5 72 54 48 66 80 43 +403 382 5 71 55 47 71 90 48 +404 382 5 73 58 52 67 92 53 +405 382 5 72 56 53 57 84 51 +406 382 5 70 54 46 50 56 34 +407 382 5 70 51 45 64 55 32 +408 382 5 70 53 46 65 50 29 +116 383 5 68 50 45 57 65 36 +117 383 5 70 52 45 57 62 37 +118 383 5 68 53 42 60 58 34 +119 383 5 67 52 44 64 62 33 +120 383 5 69 51 44 62 53 28 +121 383 5 68 49 43 62 56 29 +122 383 5 69 54 45 63 65 36 +123 383 5 69 52 44 61 59 33 +124 383 5 70 51 44 64 63 35 +125 383 5 69 50 45 57 72 41 +126 383 5 70 54 48 53 73 43 +127 383 5 72 58 55 59 71 42 +400 383 5 70 53 45 60 70 37 +401 383 5 69 52 48 57 78 44 +402 383 5 70 56 48 67 82 48 +403 383 5 71 55 49 69 84 48 +404 383 5 72 55 51 64 81 48 +405 383 5 74 56 50 58 79 47 +406 383 5 69 55 46 58 66 38 +407 383 5 65 52 43 60 67 41 +408 383 5 72 52 46 61 58 34 +116 384 5 67 52 44 62 58 31 +117 384 5 69 52 41 58 63 35 +118 384 5 70 52 43 61 60 36 +119 384 5 67 52 44 64 62 33 +120 384 5 67 50 45 62 60 34 +121 384 5 68 51 43 63 56 31 +122 384 5 70 52 43 60 65 37 +123 384 5 70 51 47 55 67 39 +124 384 5 68 50 45 57 60 33 +125 384 5 70 53 44 61 69 38 +126 384 5 72 56 47 60 78 46 +127 384 5 73 59 52 70 95 54 +400 384 5 71 54 44 60 73 40 +401 384 5 69 56 48 66 79 46 +402 384 5 70 55 50 60 75 42 +403 384 5 69 53 45 63 77 45 +404 384 5 70 53 43 60 68 41 +405 384 5 70 54 49 64 77 44 +406 384 5 71 58 52 62 73 48 +407 384 5 71 58 52 62 73 48 +408 384 5 76 60 56 63 70 42 +116 385 5 69 50 41 57 59 33 +117 385 5 69 50 43 58 60 32 +118 385 5 71 52 43 62 60 31 +119 385 5 68 50 43 64 61 33 +120 385 5 68 51 45 60 63 35 +121 385 5 67 50 41 59 57 31 +122 385 5 67 51 43 63 56 31 +123 385 5 67 51 45 58 65 37 +124 385 5 67 49 43 55 55 30 +125 385 5 69 52 48 63 66 38 +126 385 5 71 56 47 69 83 44 +127 385 5 68 53 46 63 83 48 +228 385 4 82 64 66 80 71 44 +229 385 4 72 60 56 83 63 37 +116 386 5 68 49 45 56 57 33 +117 386 5 68 49 45 56 57 33 +118 386 5 68 50 43 61 56 30 +119 386 5 67 52 45 64 60 33 +120 386 5 67 50 44 61 59 30 +121 386 5 68 52 45 60 60 33 +122 386 5 69 52 46 62 63 34 +123 386 5 66 51 45 63 64 37 +124 386 5 67 49 44 56 67 36 +125 386 5 72 54 47 70 78 43 +126 386 5 71 57 48 69 88 46 +127 386 5 70 51 43 55 65 38 +228 386 4 82 67 74 76 96 64 +229 386 4 78 68 67 85 112 68 +230 386 4 80 66 66 87 94 57 +231 386 4 76 61 60 86 82 48 +116 387 5 70 50 44 56 63 37 +117 387 5 70 52 42 61 62 36 +118 387 5 72 52 47 59 68 39 +119 387 5 68 50 45 61 59 33 +120 387 5 67 50 42 60 57 30 +121 387 5 68 52 47 65 67 37 +122 387 5 68 54 46 62 77 45 +123 387 5 70 55 48 56 71 42 +124 387 5 73 54 51 64 86 47 +125 387 5 72 54 47 70 78 43 +126 387 5 69 52 46 67 78 45 +127 387 5 67 51 46 55 72 43 +228 387 4 71 53 54 64 89 55 +229 387 4 78 63 60 70 94 58 +230 387 4 84 71 72 78 98 65 +231 387 4 85 73 77 76 87 62 +116 388 5 71 51 44 58 66 38 +117 388 5 71 55 47 63 74 44 +118 388 5 71 55 51 56 79 47 +119 388 5 68 50 45 59 62 34 +120 388 5 70 53 48 66 71 40 +121 388 5 70 53 48 57 76 44 +122 388 5 69 52 48 58 72 43 +123 388 5 71 55 50 68 80 45 +124 388 5 69 49 44 53 66 37 +125 388 5 68 51 45 60 69 41 +126 388 5 69 55 47 59 73 44 +127 388 5 70 58 47 62 80 44 +228 388 4 68 51 47 65 66 39 +229 388 4 78 61 57 74 78 43 +230 388 4 87 75 76 74 96 65 +231 388 4 89 79 82 85 100 68 +232 388 4 75 60 56 79 79 45 +116 389 5 68 51 47 58 72 41 +117 389 5 70 54 50 62 80 46 +118 389 5 70 52 49 53 76 44 +119 389 5 71 53 50 57 77 45 +120 389 5 72 54 49 59 77 46 +121 389 5 67 51 46 54 68 40 +122 389 5 69 54 49 67 80 44 +123 389 5 69 51 45 56 69 38 +124 389 5 67 46 41 50 52 30 +125 389 5 67 51 45 52 64 37 +126 389 5 69 55 45 60 70 41 +127 389 5 70 55 47 58 78 45 +228 389 4 73 57 57 70 81 47 +229 389 4 79 63 64 74 103 58 +230 389 4 81 71 71 77 102 63 +231 389 4 81 71 67 86 102 68 +232 389 4 84 72 71 85 86 53 +116 390 5 71 53 48 58 71 38 +117 390 5 70 53 48 56 77 46 +118 390 5 71 51 47 53 72 42 +119 390 5 69 54 50 54 78 47 +120 390 5 72 53 48 53 76 46 +121 390 5 69 55 50 62 78 46 +122 390 5 71 57 54 65 87 49 +123 390 5 69 49 44 44 67 37 +124 390 5 67 48 42 53 53 30 +125 390 5 67 49 44 56 57 33 +126 390 5 70 52 45 56 66 38 +127 390 5 70 53 45 56 73 43 +228 390 4 79 68 68 75 98 61 +229 390 4 83 72 72 76 106 68 +230 390 4 84 71 69 85 103 59 +231 390 4 81 71 67 91 104 66 +232 390 4 79 69 62 92 97 61 +116 391 5 72 54 47 57 78 46 +117 391 5 68 53 48 57 72 41 +118 391 5 71 50 46 57 67 39 +119 391 5 66 50 44 54 63 38 +120 391 5 69 51 44 60 64 39 +121 391 5 75 57 55 66 89 52 +122 391 5 71 53 52 51 81 48 +123 391 5 68 49 44 46 57 34 +124 391 5 69 51 45 55 58 35 +125 391 5 70 49 45 65 58 32 +126 391 5 69 50 43 55 61 34 +127 391 5 68 52 44 54 62 36 +228 391 4 78 66 64 82 98 64 +229 391 4 83 70 69 83 101 67 +230 391 4 83 71 67 89 102 62 +231 391 4 81 70 66 96 106 61 +232 391 4 80 69 64 91 102 64 +116 392 5 71 54 50 54 81 48 +117 392 5 70 54 48 59 68 39 +118 392 5 71 50 47 62 63 35 +119 392 5 67 50 40 58 54 29 +120 392 5 69 53 47 70 70 39 +121 392 5 72 54 53 55 80 48 +122 392 5 68 48 42 45 59 36 +123 392 5 69 48 41 54 55 32 +124 392 5 69 51 44 56 61 37 +125 392 5 70 51 43 60 58 34 +126 392 5 66 49 41 59 57 33 +127 392 5 66 49 43 56 54 30 +228 392 4 90 75 78 83 109 71 +229 392 4 79 68 62 93 96 61 +230 392 4 72 61 52 104 89 48 +231 392 4 75 59 52 92 82 42 +232 392 4 80 67 64 90 93 57 +117 393 5 71 53 55 64 81 47 +118 393 5 72 56 54 58 93 52 +119 393 5 68 50 42 65 61 33 +120 393 5 71 56 55 66 86 49 +121 393 5 68 50 48 45 67 43 +122 393 5 65 46 41 54 45 27 +123 393 5 68 49 43 62 59 30 +124 393 5 66 50 43 58 57 31 +125 393 5 68 50 40 55 55 30 +126 393 5 67 49 42 62 56 28 +127 393 5 66 49 42 63 58 33 +228 393 4 88 74 74 88 99 65 +229 393 4 75 62 58 89 80 52 +230 393 4 71 57 46 101 76 40 +231 393 4 70 54 41 104 82 41 +232 393 4 75 60 51 87 77 46 +267 393 4 76 61 57 63 75 50 +268 393 4 77 60 57 67 98 61 +117 394 5 75 57 61 62 109 65 +118 394 5 67 53 49 49 74 44 +119 394 5 70 52 50 51 76 48 +120 394 5 68 45 40 49 49 29 +121 394 5 68 49 42 62 55 28 +122 394 5 69 52 47 65 64 34 +123 394 5 67 50 46 61 55 29 +124 394 5 70 50 42 60 53 30 +125 394 5 69 50 41 60 52 30 +126 394 5 69 49 41 65 55 29 +127 394 5 66 50 45 63 60 32 +267 394 4 73 63 60 79 89 53 +268 394 4 81 69 66 84 107 65 +269 394 4 75 64 57 86 101 60 +270 394 4 78 64 57 90 96 52 +271 394 4 85 75 72 99 100 60 +272 394 4 84 76 72 96 99 60 +117 395 5 67 53 49 49 74 44 +118 395 5 69 48 42 56 50 29 +119 395 5 67 48 42 57 48 26 +120 395 5 69 52 46 67 67 35 +121 395 5 70 52 49 62 70 43 +122 395 5 71 52 48 57 66 40 +123 395 5 71 53 47 59 62 34 +124 395 5 70 51 43 64 59 32 +125 395 5 69 53 47 63 64 35 +126 395 5 69 52 45 58 62 36 +127 395 5 67 50 43 59 57 33 +267 395 4 80 67 66 86 91 55 +268 395 4 87 77 77 85 109 72 +269 395 4 82 70 67 89 100 59 +270 395 4 75 62 55 103 82 43 +271 395 4 70 59 48 109 89 45 +272 395 4 80 71 72 89 102 64 +273 395 4 90 80 91 72 104 76 +267 396 4 89 80 80 91 116 77 +268 396 4 89 80 80 91 116 77 +269 396 4 92 83 84 90 119 80 +270 396 4 86 73 69 96 94 57 +271 396 4 76 61 54 92 75 36 +272 396 4 79 65 67 75 97 60 +273 396 4 88 76 82 68 114 83 +267 397 4 85 75 76 87 108 70 +268 397 4 89 79 79 83 94 66 +269 397 4 101 87 89 68 97 73 +270 397 4 84 70 65 84 88 58 +271 397 4 73 59 50 92 83 47 +272 397 4 87 75 75 78 106 74 +273 397 4 80 67 66 80 93 60 +267 398 4 83 71 72 84 106 65 +268 398 4 85 74 72 85 102 64 +269 398 4 84 70 65 84 86 62 +270 398 4 72 59 51 90 84 54 +271 398 4 73 61 54 94 76 40 +272 398 4 86 71 68 79 92 58 +273 398 4 83 69 65 67 94 60 +186 399 6 76 64 69 76 94 54 +187 399 6 81 69 72 69 104 66 +188 399 6 76 62 63 68 86 51 +267 399 4 82 71 69 79 102 64 +268 399 4 85 74 72 85 102 64 +269 399 4 83 71 68 90 89 52 +270 399 4 76 61 54 94 79 42 +271 399 4 72 56 46 91 78 43 +272 399 4 75 60 52 84 78 47 +273 399 4 76 62 59 77 86 52 +185 400 6 74 59 62 60 76 46 +186 400 6 76 64 69 76 94 54 +187 400 6 72 57 56 49 75 41 +188 400 6 70 51 46 35 33 18 +267 400 4 81 70 68 81 89 56 +268 400 4 77 68 64 93 109 61 +269 400 4 85 71 70 94 95 61 +270 400 4 79 65 58 95 85 52 +271 400 4 86 75 73 90 93 61 +272 400 4 82 73 70 88 77 53 +273 400 4 73 58 53 86 71 38 +185 401 6 76 61 60 69 91 49 +186 401 6 68 48 40 25 24 16 +187 401 6 66 45 38 17 10 8 +188 401 6 66 46 33 13 10 10 +269 401 4 81 67 65 92 88 57 +270 401 4 86 72 70 85 89 67 +271 401 4 84 73 76 101 92 60 +272 401 4 84 69 70 84 81 55 +273 401 4 72 55 48 80 64 36 +274 401 4 79 64 58 85 80 50 +186 402 6 69 48 42 26 29 19 +271 402 4 75 61 55 100 87 46 +272 402 4 69 54 46 88 66 35 +273 402 4 70 54 41 86 64 34 +274 402 4 79 64 58 85 80 50 274 403 4 79 67 64 103 103 56 \ No newline at end of file diff --git a/pyspatialml/datasets/meuse.py b/pyspatialml/datasets/meuse.py index b88d900..5efe2d0 100644 --- a/pyspatialml/datasets/meuse.py +++ b/pyspatialml/datasets/meuse.py @@ -1,29 +1,29 @@ -import os - -chnl_dist = os.path.join(os.path.dirname(__file__), 'chnl_dist.tif') -dem = os.path.join(os.path.dirname(__file__), 'dem.tif') -dist = os.path.join(os.path.dirname(__file__), 'dist.tif') -ffreq = os.path.join(os.path.dirname(__file__), 'ffreq.tif') -landimg2 = os.path.join(os.path.dirname(__file__), 'landimg2.tif') -landimg3 = os.path.join(os.path.dirname(__file__), 'landimg3.tif') -landimg4 = os.path.join(os.path.dirname(__file__), 'landimg4.tif') -mrvbf = os.path.join(os.path.dirname(__file__), 'mrvbf.tif') -rsp = os.path.join(os.path.dirname(__file__), 'rsp.tif') -slope = os.path.join(os.path.dirname(__file__), 'slope.tif') -soil = os.path.join(os.path.dirname(__file__), 'soil.tif') -twi = os.path.join(os.path.dirname(__file__), 'twi.tif') -meuse = os.path.join(os.path.dirname(__file__), 'meuse.shp') - -predictors = [ - chnl_dist, - dem, - dist, - ffreq, - landimg2, - landimg3, - landimg4, - mrvbf, - rsp, - slope, - soil, - twi] +import os + +chnl_dist = os.path.join(os.path.dirname(__file__), 'chnl_dist.tif') +dem = os.path.join(os.path.dirname(__file__), 'dem.tif') +dist = os.path.join(os.path.dirname(__file__), 'dist.tif') +ffreq = os.path.join(os.path.dirname(__file__), 'ffreq.tif') +landimg2 = os.path.join(os.path.dirname(__file__), 'landimg2.tif') +landimg3 = os.path.join(os.path.dirname(__file__), 'landimg3.tif') +landimg4 = os.path.join(os.path.dirname(__file__), 'landimg4.tif') +mrvbf = os.path.join(os.path.dirname(__file__), 'mrvbf.tif') +rsp = os.path.join(os.path.dirname(__file__), 'rsp.tif') +slope = os.path.join(os.path.dirname(__file__), 'slope.tif') +soil = os.path.join(os.path.dirname(__file__), 'soil.tif') +twi = os.path.join(os.path.dirname(__file__), 'twi.tif') +meuse = os.path.join(os.path.dirname(__file__), 'meuse.shp') + +predictors = [ + chnl_dist, + dem, + dist, + ffreq, + landimg2, + landimg3, + landimg4, + mrvbf, + rsp, + slope, + soil, + twi] diff --git a/pyspatialml/datasets/nc.py b/pyspatialml/datasets/nc.py index 008413e..50f6d17 100644 --- a/pyspatialml/datasets/nc.py +++ b/pyspatialml/datasets/nc.py @@ -1,14 +1,14 @@ -import os - -band1 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_10.tif') -band2 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_20.tif') -band3 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_30.tif') -band4 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_40.tif') -band5 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_50.tif') -band7 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_70.tif') -strata = os.path.join(os.path.dirname(__file__), 'strata.tif') -multiband = os.path.join(os.path.dirname(__file__), 'landsat_multiband.tif') -labelled_pixels = os.path.join(os.path.dirname(__file__), 'landsat96_labelled_pixels.tif') -points = os.path.join(os.path.dirname(__file__), 'landsat96_points.shp') -polygons = os.path.join(os.path.dirname(__file__), 'landsat96_polygons.shp') -extracted_pixels = os.path.join(os.path.dirname(__file__), 'extracted_pixels.txt') +import os + +band1 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_10.tif') +band2 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_20.tif') +band3 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_30.tif') +band4 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_40.tif') +band5 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_50.tif') +band7 = os.path.join(os.path.dirname(__file__), 'lsat7_2000_70.tif') +strata = os.path.join(os.path.dirname(__file__), 'strata.tif') +multiband = os.path.join(os.path.dirname(__file__), 'landsat_multiband.tif') +labelled_pixels = os.path.join(os.path.dirname(__file__), 'landsat96_labelled_pixels.tif') +points = os.path.join(os.path.dirname(__file__), 'landsat96_points.shp') +polygons = os.path.join(os.path.dirname(__file__), 'landsat96_polygons.shp') +extracted_pixels = os.path.join(os.path.dirname(__file__), 'extracted_pixels.txt') diff --git a/pyspatialml/locindexer.py b/pyspatialml/locindexer.py index 20a6d60..72552dc 100644 --- a/pyspatialml/locindexer.py +++ b/pyspatialml/locindexer.py @@ -1,239 +1,239 @@ -import pandas as pd -from collections.abc import MutableMapping -from . import raster, rasterlayer - - -class _LocIndexer(MutableMapping): - """Access pyspatialml.RasterLayer objects by using a key. - - Represents a structure similar to a dict but allows access using a - list of keys (not just a single key). - """ - - def __init__(self, *args, **kw): - self.__dict__.update(*args, **kw) - - def __getitem__(self, key): - """Defines the subset method for the _LocIndexer. Allows the - contained RasterLayer objects to be subset using a either - single, or multiple labels corresponding to the names of each - RasterLayer. - - Parameters - ---------- - key : a single str, or a list of str - - Returns - ------- - Returns a RasterLayer if only a single item is subset, or a - Raster if multiple items are subset. - - """ - if isinstance(key, str): - new = self.__dict__[key] - else: - selected = [] - for i in key: - if i in self.names is False: - raise KeyError("key not present in Raster object") - else: - selected.append(self.__dict__[i]) - new = raster.Raster(selected) - return new - - def __setitem__(self, key, value): - """Allows a RasterLayer object to be assigned to a name within - a Raster object. This automatically updates the indexer with - the layer, and adds the RasterLayer's name as an attribute in - the Raster. - - Parameters - ---------- - key : str - The key to use for the assignment: - - value : pyspatialml.RasterLayer - A single RasterLayer object to assign to the key. - """ - if isinstance(value, rasterlayer.RasterLayer): - self.__dict__[key] = value - else: - raise ValueError("value is not a RasterLayer object") - - def __iter__(self): - """Iterates through keys""" - return iter(self._keys) - - def __len__(self): - """Number of layers in the indexer""" - return len(self.__dict__) - len(self._internal) - - def __delitem__(self, key): - """Delete a key:value pair""" - self.__dict__.pop(key) - - def __repr__(self): - print("Raster Object Containing {n} Layers".format(n=self.count)) - meta = pd.DataFrame( - { - "attribute": ["names", "files", "rows", "cols", "res", "nodatavals"], - "values": [ - list(self.names), - self.files, - self.shape[0], - self.shape[1], - self.res, - self.nodatavals, - ], - } - ) - print(meta) - - return "" - - @property - def _keys(self): - d = {k: v for (k, v) in self.__dict__.items() if k not in self._internal} - return d.keys() - - def _rename_inplace(self, old, new): - """Rename a RasterLayer from `old` to `new. This method renames - the layer in the indexer and renames the equivalent attribute - in the parent Raster object. - - Parameters - ---------- - old : str - Name of the existing key. - - new : str - Name to use to rename the existing key. - """ - # rename the index by rebuilding the dict - original_keys = list(self.__dict__.keys()) - new_keys = [new if i == old else i for i in original_keys] - new_dict = dict(zip(new_keys, self.__dict__.values())) - self.__dict__ = new_dict - - # update the internal name of a RasterLayer - self.__dict__[new].name = new - - @property - def loc(self): - """Alias for the getter method of the indexer""" - return self - - @loc.setter - def loc(self, key, value): - """Alias for the setter method if the indexer""" - self.__dict__[key] = value - - @property - def iloc(self): - """Reference to an integer-based indexer to access the layers - by integer position rather than label""" - return _iLocIndexer(self) - - @property - def names(self): - return self._keys - - @names.setter - def names(self, value): - if isinstance(value, str): - value = [value] - - if len(value) != self.count: - raise ValueError( - "Length of new names has to equal the number of layers in the Raster" - ) - - renamer = {old: new for (old, new) in zip(self.names, value)} - self.rename(renamer, in_place=True) - - -class _iLocIndexer(object): - """Access pyspatialml.RasterLayer objects using an index position - - A wrapper around _LocIndexer to enable integer-based indexing of - the items in the OrderedDict. Setting and getting items can occur - using a single index position, a list or tuple of positions, or a - slice of positions. - - Methods - ------- - __getitem__ : index - Subset RasterLayers using an integer index, a slice of indexes, - or a list/tuple of indexes. Returns a RasterLayer is a single - item is subset, or a Raster if multiple layers are subset. - - __setitem__ : index, value - Assign a RasterLayer to a index position within the indexer. - The index can be a single integer position, a slice of - positions, or a list/tuple of positions. This method also - updates the parent Raster object's attributes with the names - of the new RasterLayers that were passed as the value. - """ - - def __init__(self, loc_indexer): - """Initiate a _iLocIndexer - - Parameters - ---------- - loc_indexer : pyspatialml.raster._LocIndexer - An instance of a _LocIndexer. - """ - self._index = loc_indexer - - def __setitem__(self, index, value): - if isinstance(index, int): - key = list(self._index.keys())[index] - self._index[key] = value - - if isinstance(index, slice): - start = index.start - stop = index.stop - step = index.step - - if start is None: - start = 0 - if stop is None: - stop = self.count - if step is None: - step = 1 - - index = list(range(start, stop, step)) - - if isinstance(index, (list, tuple)): - for i, v in zip(index, value): - key = list(self._index.keys())[i] - self._index[key] = v - - def __getitem__(self, index): - if isinstance(index, int): - key = list(self._index.keys())[index] - selected = self._index[key] - - if isinstance(index, slice): - start = index.start - stop = index.stop - step = index.step - - if start is None: - start = 0 - - if stop is None: - stop = self.count - - if step is None: - step = 1 - - index = list(range(start, stop, step)) - - if isinstance(index, (list, tuple)): - key = [] - for i in index: - key.append(list(self._index.keys())[i]) - selected = raster.Raster([self._index[k] for k in key]) - - return selected +import pandas as pd +from collections.abc import MutableMapping +from . import raster, rasterlayer + + +class _LocIndexer(MutableMapping): + """Access pyspatialml.RasterLayer objects by using a key. + + Represents a structure similar to a dict but allows access using a + list of keys (not just a single key). + """ + + def __init__(self, *args, **kw): + self.__dict__.update(*args, **kw) + + def __getitem__(self, key): + """Defines the subset method for the _LocIndexer. Allows the + contained RasterLayer objects to be subset using a either + single, or multiple labels corresponding to the names of each + RasterLayer. + + Parameters + ---------- + key : a single str, or a list of str + + Returns + ------- + Returns a RasterLayer if only a single item is subset, or a + Raster if multiple items are subset. + + """ + if isinstance(key, str): + new = self.__dict__[key] + else: + selected = [] + for i in key: + if i in self.names is False: + raise KeyError("key not present in Raster object") + else: + selected.append(self.__dict__[i]) + new = raster.Raster(selected) + return new + + def __setitem__(self, key, value): + """Allows a RasterLayer object to be assigned to a name within + a Raster object. This automatically updates the indexer with + the layer, and adds the RasterLayer's name as an attribute in + the Raster. + + Parameters + ---------- + key : str + The key to use for the assignment: + + value : pyspatialml.RasterLayer + A single RasterLayer object to assign to the key. + """ + if isinstance(value, rasterlayer.RasterLayer): + self.__dict__[key] = value + else: + raise ValueError("value is not a RasterLayer object") + + def __iter__(self): + """Iterates through keys""" + return iter(self._keys) + + def __len__(self): + """Number of layers in the indexer""" + return len(self.__dict__) - len(self._internal) + + def __delitem__(self, key): + """Delete a key:value pair""" + self.__dict__.pop(key) + + def __repr__(self): + print("Raster Object Containing {n} Layers".format(n=self.count)) + meta = pd.DataFrame( + { + "attribute": ["names", "files", "rows", "cols", "res", "nodatavals"], + "values": [ + list(self.names), + self.files, + self.shape[0], + self.shape[1], + self.res, + self.nodatavals, + ], + } + ) + print(meta) + + return "" + + @property + def _keys(self): + d = {k: v for (k, v) in self.__dict__.items() if k not in self._internal} + return d.keys() + + def _rename_inplace(self, old, new): + """Rename a RasterLayer from `old` to `new. This method renames + the layer in the indexer and renames the equivalent attribute + in the parent Raster object. + + Parameters + ---------- + old : str + Name of the existing key. + + new : str + Name to use to rename the existing key. + """ + # rename the index by rebuilding the dict + original_keys = list(self.__dict__.keys()) + new_keys = [new if i == old else i for i in original_keys] + new_dict = dict(zip(new_keys, self.__dict__.values())) + self.__dict__ = new_dict + + # update the internal name of a RasterLayer + self.__dict__[new].name = new + + @property + def loc(self): + """Alias for the getter method of the indexer""" + return self + + @loc.setter + def loc(self, key, value): + """Alias for the setter method if the indexer""" + self.__dict__[key] = value + + @property + def iloc(self): + """Reference to an integer-based indexer to access the layers + by integer position rather than label""" + return _iLocIndexer(self) + + @property + def names(self): + return self._keys + + @names.setter + def names(self, value): + if isinstance(value, str): + value = [value] + + if len(value) != self.count: + raise ValueError( + "Length of new names has to equal the number of layers in the Raster" + ) + + renamer = {old: new for (old, new) in zip(self.names, value)} + self.rename(renamer, in_place=True) + + +class _iLocIndexer(object): + """Access pyspatialml.RasterLayer objects using an index position + + A wrapper around _LocIndexer to enable integer-based indexing of + the items in the OrderedDict. Setting and getting items can occur + using a single index position, a list or tuple of positions, or a + slice of positions. + + Methods + ------- + __getitem__ : index + Subset RasterLayers using an integer index, a slice of indexes, + or a list/tuple of indexes. Returns a RasterLayer is a single + item is subset, or a Raster if multiple layers are subset. + + __setitem__ : index, value + Assign a RasterLayer to a index position within the indexer. + The index can be a single integer position, a slice of + positions, or a list/tuple of positions. This method also + updates the parent Raster object's attributes with the names + of the new RasterLayers that were passed as the value. + """ + + def __init__(self, loc_indexer): + """Initiate a _iLocIndexer + + Parameters + ---------- + loc_indexer : pyspatialml.raster._LocIndexer + An instance of a _LocIndexer. + """ + self._index = loc_indexer + + def __setitem__(self, index, value): + if isinstance(index, int): + key = list(self._index.keys())[index] + self._index[key] = value + + if isinstance(index, slice): + start = index.start + stop = index.stop + step = index.step + + if start is None: + start = 0 + if stop is None: + stop = self.count + if step is None: + step = 1 + + index = list(range(start, stop, step)) + + if isinstance(index, (list, tuple)): + for i, v in zip(index, value): + key = list(self._index.keys())[i] + self._index[key] = v + + def __getitem__(self, index): + if isinstance(index, int): + key = list(self._index.keys())[index] + selected = self._index[key] + + if isinstance(index, slice): + start = index.start + stop = index.stop + step = index.step + + if start is None: + start = 0 + + if stop is None: + stop = self.count + + if step is None: + step = 1 + + index = list(range(start, stop, step)) + + if isinstance(index, (list, tuple)): + key = [] + for i in index: + key.append(list(self._index.keys())[i]) + selected = raster.Raster([self._index[k] for k in key]) + + return selected diff --git a/pyspatialml/preprocessing.py b/pyspatialml/preprocessing.py index 6177c0e..67610c1 100644 --- a/pyspatialml/preprocessing.py +++ b/pyspatialml/preprocessing.py @@ -1,293 +1,293 @@ -from copy import deepcopy - -import numpy as np -import rasterio -from scipy import ndimage - -from .raster import Raster - - -def one_hot_encode(layer, file_path, categories=None, driver="GTiff"): - """One-hot encoding of a RasterLayer. - - Parameters - ---------- - layer : pyspatialml.RasterLayer - Containing categories to perform one-hot encoding on. - - file_path : str - File path to save one-hot encoded raster. - - categories : list, ndarray, optional - Optional list of categories to extract. Default performs one-hot - encoding on all categorical values in the input layer. - - driver : str, options. Default is 'GTiff' - GDAL-compatible driver. - - Returns - ------- - pyspatialml.Raster - Each categorical value is encoded as a layer with a Raster object. - """ - arr = layer.read(masked=True) - - if categories is None: - categories = np.unique(arr) - categories = categories[~categories.mask] - categories = categories.data.astype("int32") - - arr_ohe = np.ma.zeros((len(categories), arr.shape[0], arr.shape[1]), dtype="int32") - names = [] - prefix = layer.names[0] - - for i, cat in enumerate(categories): - enc = deepcopy(arr) - enc[enc != cat] = 0 - enc[enc == cat] = 1 - arr_ohe[i, :, :] = enc - - names.append("_".join([prefix, "cat", str(cat)])) - - # create new stack - meta = deepcopy(layer.ds.meta) - meta["driver"] = driver - meta["nodata"] = -99999 - meta["count"] = arr_ohe.shape[0] - meta["dtype"] = "int32" - - with rasterio.open(file_path, mode="w", **meta) as dst: - dst.write(arr_ohe) - - new_raster = Raster(file_path) - new_raster.rename({old: new for old, new in zip(new_raster.names, names)}) - - return new_raster - - -def xy_coordinates(layer, file_path, driver="GTiff"): - """ - Fill 2d arrays with their x,y indices. - - Parameters - ---------- - layer : pyspatialml.RasterLayer, or rasterio.DatasetReader - RasterLayer to use as a template. - - file_path : str - File path to save to the resulting Raster object.s - - driver : str, options. Default is 'GTiff' - GDAL driver to use to save raster. - - Returns - ------- - pyspatialml.Raster object - """ - - arr = np.zeros(layer.shape, dtype=np.float32) - arr = arr[np.newaxis, :, :] - xyarrays = np.repeat(arr[0:1, :, :], 2, axis=0) - xx, xy = np.meshgrid(np.arange(arr.shape[2]), np.arange(arr.shape[1])) - xyarrays[0, :, :] = xx - xyarrays[1, :, :] = xy - - # create new stack - meta = deepcopy(layer.meta) - meta["driver"] = driver - meta["count"] = 2 - meta["dtype"] = xyarrays.dtype - - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(xyarrays) - - new_raster = Raster(file_path) - names = ["x_coordinates", "y_coordinates"] - new_raster.rename( - {old: new for old, new in zip(new_raster.names, names)}, - in_place=True - ) - - return new_raster - - -def rotated_coordinates(layer, file_path, n_angles=8, driver="GTiff"): - """Generate 2d arrays with n_angles rotated coordinates. - - Parameters - ---------- - layer : pyspatialml.RasterLayer, or rasterio.DatasetReader - RasterLayer to use as a template. - - n_angles : int, optional. Default is 8 - Number of angles to rotate coordinate system by. - - driver : str, optional. Default is 'GTiff' - GDAL driver to use to save raster. - - Returns - ------- - pyspatialml.Raster - """ - # define x and y grid dimensions - xmin, ymin, xmax, ymax = 0, 0, layer.shape[1], layer.shape[0] - x_range = np.arange(start=xmin, stop=xmax, step=1) - y_range = np.arange(start=ymin, stop=ymax, step=1, dtype=np.float32) - - X_var, Y_var, _ = np.meshgrid(x_range, y_range, n_angles) - angles = np.deg2rad(np.linspace(0, 180, n_angles, endpoint=False)) - grids_directional = X_var + np.tan(angles) * Y_var - - # reorder to band, row, col order - grids_directional = grids_directional.transpose((2, 0, 1)) - - # create new stack - meta = deepcopy(layer.meta) - meta["driver"] = driver - meta["count"] = n_angles - meta["dtype"] = grids_directional.dtype - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(grids_directional) - - new_raster = Raster(file_path) - names = ["angle_" + str(i + 1) for i in range(n_angles)] - new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, - in_place=True) - - return new_raster - - -def distance_to_corners(layer, file_path, driver="GTiff"): - """Generate buffer distances to corner and centre coordinates of raster - extent. - - Parameters - ---------- - layer : pyspatialml.RasterLayer, or rasterio.DatasetReader - - file_path : str - File path to save to the resulting Raster object - - driver : str, optional. Default is 'GTiff' - GDAL driver to use to save raster. - - Returns - ------- - pyspatialml.Raster object - """ - - names = ["top_left", "top_right", "bottom_left", "bottom_right", "centre_indices"] - - rows = np.asarray( - [0, 0, layer.shape[0] - 1, layer.shape[0] - 1, int(layer.shape[0] / 2)] - ) - cols = np.asarray( - [0, layer.shape[1] - 1, 0, layer.shape[1] - 1, int(layer.shape[1] / 2)] - ) - - # euclidean distances - arr = _grid_distance(layer.shape, rows, cols) - - # create new stack - meta = deepcopy(layer.meta) - meta["driver"] = driver - meta["count"] = 5 - meta["dtype"] = arr.dtype - - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(arr) - - new_raster = Raster(file_path) - new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, - in_place=True) - - return new_raster - - -def _grid_distance(shape, rows, cols): - """Generate buffer distances to x,y coordinates. - - Parameters - ---------- - shape : tuple - shape of numpy array (rows, cols) to create buffer distances within. - rows : 1d numpy array - array of row indexes. - cols : 1d numpy array - array of column indexes. - - Returns - ------- - ndarray - 3d numpy array of euclidean grid distances to each x,y coordinate pair - [band, row, col]. - """ - - # create buffer distances - grids_buffers = np.zeros((shape[0], shape[1], rows.shape[0]), dtype=np.float32) - - for i, (y, x) in enumerate(zip(rows, cols)): - # create 2d array (image) with pick indexes set to z - point_arr = np.zeros((shape[0], shape[1])) - point_arr[y, x] = 1 - buffer = ndimage.morphology.distance_transform_edt(1 - point_arr) - grids_buffers[:, :, i] = buffer - - # reorder to band, row, column - grids_buffers = grids_buffers.transpose((2, 0, 1)) - - return grids_buffers - - -def distance_to_samples(layer, file_path, rows, cols, driver="GTiff"): - """Generate buffer distances to x,y coordinates. - - Parameters - ---------- - layer : pyspatialml.RasterLayer, or rasterio.DatasetReader - RasterLayer to use as a template. - - file_path : str - File path to save to the resulting Raster object. - - rows : 1d numpy array - array of row indexes. - - cols : 1d numpy array - array of column indexes. - - driver : str, default='GTiff' - GDAL driver to use to save raster. - - Returns - ------- - pyspatialml.Raster object - """ - # some checks - if isinstance(rows, list): - rows = np.asarray(rows) - - if isinstance(cols, list): - cols = np.asarray(cols) - - if rows.shape != cols.shape: - raise ValueError("rows and cols must have same dimensions") - - shape = layer.shape - arr = _grid_distance(shape, rows, cols) - - # create new stack - meta = deepcopy(layer.meta) - meta["driver"] = driver - meta["count"] = arr.shape[0] - meta["dtype"] = arr.dtype - - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(arr) - - names = ["dist_sample" + str(i + 1) for i in range(len(rows))] - new_raster = Raster(file_path) - new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, - in_place=True) - - return new_raster +from copy import deepcopy + +import numpy as np +import rasterio +from scipy import ndimage + +from .raster import Raster + + +def one_hot_encode(layer, file_path, categories=None, driver="GTiff"): + """One-hot encoding of a RasterLayer. + + Parameters + ---------- + layer : pyspatialml.RasterLayer + Containing categories to perform one-hot encoding on. + + file_path : str + File path to save one-hot encoded raster. + + categories : list, ndarray, optional + Optional list of categories to extract. Default performs one-hot + encoding on all categorical values in the input layer. + + driver : str, options. Default is 'GTiff' + GDAL-compatible driver. + + Returns + ------- + pyspatialml.Raster + Each categorical value is encoded as a layer with a Raster object. + """ + arr = layer.read(masked=True) + + if categories is None: + categories = np.unique(arr) + categories = categories[~categories.mask] + categories = categories.data.astype("int32") + + arr_ohe = np.ma.zeros((len(categories), arr.shape[0], arr.shape[1]), dtype="int32") + names = [] + prefix = layer.names[0] + + for i, cat in enumerate(categories): + enc = deepcopy(arr) + enc[enc != cat] = 0 + enc[enc == cat] = 1 + arr_ohe[i, :, :] = enc + + names.append("_".join([prefix, "cat", str(cat)])) + + # create new stack + meta = deepcopy(layer.ds.meta) + meta["driver"] = driver + meta["nodata"] = -99999 + meta["count"] = arr_ohe.shape[0] + meta["dtype"] = "int32" + + with rasterio.open(file_path, mode="w", **meta) as dst: + dst.write(arr_ohe) + + new_raster = Raster(file_path) + new_raster.rename({old: new for old, new in zip(new_raster.names, names)}) + + return new_raster + + +def xy_coordinates(layer, file_path, driver="GTiff"): + """ + Fill 2d arrays with their x,y indices. + + Parameters + ---------- + layer : pyspatialml.RasterLayer, or rasterio.DatasetReader + RasterLayer to use as a template. + + file_path : str + File path to save to the resulting Raster object.s + + driver : str, options. Default is 'GTiff' + GDAL driver to use to save raster. + + Returns + ------- + pyspatialml.Raster object + """ + + arr = np.zeros(layer.shape, dtype=np.float32) + arr = arr[np.newaxis, :, :] + xyarrays = np.repeat(arr[0:1, :, :], 2, axis=0) + xx, xy = np.meshgrid(np.arange(arr.shape[2]), np.arange(arr.shape[1])) + xyarrays[0, :, :] = xx + xyarrays[1, :, :] = xy + + # create new stack + meta = deepcopy(layer.meta) + meta["driver"] = driver + meta["count"] = 2 + meta["dtype"] = xyarrays.dtype + + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(xyarrays) + + new_raster = Raster(file_path) + names = ["x_coordinates", "y_coordinates"] + new_raster.rename( + {old: new for old, new in zip(new_raster.names, names)}, + in_place=True + ) + + return new_raster + + +def rotated_coordinates(layer, file_path, n_angles=8, driver="GTiff"): + """Generate 2d arrays with n_angles rotated coordinates. + + Parameters + ---------- + layer : pyspatialml.RasterLayer, or rasterio.DatasetReader + RasterLayer to use as a template. + + n_angles : int, optional. Default is 8 + Number of angles to rotate coordinate system by. + + driver : str, optional. Default is 'GTiff' + GDAL driver to use to save raster. + + Returns + ------- + pyspatialml.Raster + """ + # define x and y grid dimensions + xmin, ymin, xmax, ymax = 0, 0, layer.shape[1], layer.shape[0] + x_range = np.arange(start=xmin, stop=xmax, step=1) + y_range = np.arange(start=ymin, stop=ymax, step=1, dtype=np.float32) + + X_var, Y_var, _ = np.meshgrid(x_range, y_range, n_angles) + angles = np.deg2rad(np.linspace(0, 180, n_angles, endpoint=False)) + grids_directional = X_var + np.tan(angles) * Y_var + + # reorder to band, row, col order + grids_directional = grids_directional.transpose((2, 0, 1)) + + # create new stack + meta = deepcopy(layer.meta) + meta["driver"] = driver + meta["count"] = n_angles + meta["dtype"] = grids_directional.dtype + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(grids_directional) + + new_raster = Raster(file_path) + names = ["angle_" + str(i + 1) for i in range(n_angles)] + new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, + in_place=True) + + return new_raster + + +def distance_to_corners(layer, file_path, driver="GTiff"): + """Generate buffer distances to corner and centre coordinates of raster + extent. + + Parameters + ---------- + layer : pyspatialml.RasterLayer, or rasterio.DatasetReader + + file_path : str + File path to save to the resulting Raster object + + driver : str, optional. Default is 'GTiff' + GDAL driver to use to save raster. + + Returns + ------- + pyspatialml.Raster object + """ + + names = ["top_left", "top_right", "bottom_left", "bottom_right", "centre_indices"] + + rows = np.asarray( + [0, 0, layer.shape[0] - 1, layer.shape[0] - 1, int(layer.shape[0] / 2)] + ) + cols = np.asarray( + [0, layer.shape[1] - 1, 0, layer.shape[1] - 1, int(layer.shape[1] / 2)] + ) + + # euclidean distances + arr = _grid_distance(layer.shape, rows, cols) + + # create new stack + meta = deepcopy(layer.meta) + meta["driver"] = driver + meta["count"] = 5 + meta["dtype"] = arr.dtype + + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(arr) + + new_raster = Raster(file_path) + new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, + in_place=True) + + return new_raster + + +def _grid_distance(shape, rows, cols): + """Generate buffer distances to x,y coordinates. + + Parameters + ---------- + shape : tuple + shape of numpy array (rows, cols) to create buffer distances within. + rows : 1d numpy array + array of row indexes. + cols : 1d numpy array + array of column indexes. + + Returns + ------- + ndarray + 3d numpy array of euclidean grid distances to each x,y coordinate pair + [band, row, col]. + """ + + # create buffer distances + grids_buffers = np.zeros((shape[0], shape[1], rows.shape[0]), dtype=np.float32) + + for i, (y, x) in enumerate(zip(rows, cols)): + # create 2d array (image) with pick indexes set to z + point_arr = np.zeros((shape[0], shape[1])) + point_arr[y, x] = 1 + buffer = ndimage.morphology.distance_transform_edt(1 - point_arr) + grids_buffers[:, :, i] = buffer + + # reorder to band, row, column + grids_buffers = grids_buffers.transpose((2, 0, 1)) + + return grids_buffers + + +def distance_to_samples(layer, file_path, rows, cols, driver="GTiff"): + """Generate buffer distances to x,y coordinates. + + Parameters + ---------- + layer : pyspatialml.RasterLayer, or rasterio.DatasetReader + RasterLayer to use as a template. + + file_path : str + File path to save to the resulting Raster object. + + rows : 1d numpy array + array of row indexes. + + cols : 1d numpy array + array of column indexes. + + driver : str, default='GTiff' + GDAL driver to use to save raster. + + Returns + ------- + pyspatialml.Raster object + """ + # some checks + if isinstance(rows, list): + rows = np.asarray(rows) + + if isinstance(cols, list): + cols = np.asarray(cols) + + if rows.shape != cols.shape: + raise ValueError("rows and cols must have same dimensions") + + shape = layer.shape + arr = _grid_distance(shape, rows, cols) + + # create new stack + meta = deepcopy(layer.meta) + meta["driver"] = driver + meta["count"] = arr.shape[0] + meta["dtype"] = arr.dtype + + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(arr) + + names = ["dist_sample" + str(i + 1) for i in range(len(rows))] + new_raster = Raster(file_path) + new_raster.rename({old: new for old, new in zip(new_raster.names, names)}, + in_place=True) + + return new_raster diff --git a/pyspatialml/raster.py b/pyspatialml/raster.py index 1ed1e58..85a90a9 100644 --- a/pyspatialml/raster.py +++ b/pyspatialml/raster.py @@ -1,2691 +1,2691 @@ -import os -import tempfile -from collections import namedtuple -from collections.abc import ValuesView -from functools import partial -from typing import Tuple -import affine - -import geopandas as gpd -import numpy as np -import pandas as pd -import rasterio -import rasterio.mask -import rasterio.plot -from rasterio import features -from rasterio.io import MemoryFile -from rasterio.sample import sample_gen -from rasterio.warp import calculate_default_transform, reproject -from rasterio.windows import Window -from rasterio.transform import rowcol -from shapely.geometry import Point -from tqdm import tqdm -from collections import Counter - -from ._plotting import RasterPlotMixin -from ._prediction import ( - predict_multioutput, - predict_output, - predict_prob, - stack_constants, -) -from ._utils import get_nodata_value -from .rasterlayer import RasterLayer -from ._rasterstats import RasterStatsMixin -from .locindexer import _LocIndexer - - -class Raster(_LocIndexer, RasterStatsMixin, RasterPlotMixin): - """Creates a collection of file-based GDAL-supported raster - datasets that share a common coordinate reference system and - geometry. - - Raster objects encapsulate RasterLayer objects, which represent - single band raster datasets that can physically be represented by - either separate single-band raster files, multi-band raster files, - or any combination of individual bands from multi-band raster and - single-band raster datasets. - - Attributes - ---------- - files : list - A list of the raster dataset files that are used in the Raster. - This does not have to be the same length as the number of - RasterLayers because some files may have multiple bands. - - meta : dict - A dict containing the raster metadata. The dict contains the - following keys/values: - - crs : the crs object - transform : the Affine.affine transform object - width : width of the Raster in pixels - height : height of the Raster in pixels - count : number of RasterLayers within the Raster - dtype : the numpy datatype that represents lowest common - denominator of the different dtypes for all of the layers - in the Raster. - - names : list - A list of the RasterLayer names. - - block_shape : tuple - The default block_shape in (rows, cols) for reading windows of data - in the Raster for out-of-memory processing. - """ - - def __init__( - self, - src, - crs=None, - transform=None, - nodata=None, - file_path=None, - driver=None, - tempdir=tempfile.tempdir, - in_memory=False, - ): - """Initiate a new Raster object - - Parameters - ---------- - src : file path, RasterLayer, rasterio dataset, or a ndarray - Initiate a Raster object from any combination of a file - path or list of file paths to GDAL-supported raster - datasets, RasterLayer objects, or directly from a rasterio - dataset or band object that is opened in 'r' or 'rw' mode. - - A Raster object can also be created directly from a numpy - array in [band, rows, cols] order. The additional arguments - `crs` and `transform` should also be provided to supply - spatial coordinate information. - - crs : rasterio.crs.CRS object (optional, default is None) - CRS object containing projection information for data if - provided as an array. - - transform : affine.Affine object (optional, default is None) - Affine object containing transform information for data if - provided as an array. - - nodata : any number (optional, default is None) - Assign a nodata value to the Raster dataset when `src` is - a ndarray. If a nodata value is not specified then it is - determined based on the minimum permissible value for the - array's data type. - - file_path : str (optional, default None) - Path to save new Raster object if created from an array. - - driver : str (optional, default=None) - A GDAL compatible driver to use when initiating a raster - from a numpy array. - - tempdir : str, default is tempfile.tempdir - Path to a directory to store temporary files that are - produced during geoprocessing operations. - - in_memory : bool, default is False - Whether to initiate the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - Returns - ------- - pyspatialml.Raster - Raster object containing the src layers stacked into a - single object. - """ - self.files = list() - self.meta = None - self._block_shape = (256, 256) - self.tempdir = tempdir - self._internal = frozenset( - ["_internal", "files", "meta", "_block_shape", "tempdir"] - ) - - src_layers = [] - - # get temporary file name if file_path is None - if file_path is None and isinstance(src, np.ndarray): - file_path, tfile = self._tempfile(file_path) - driver = "GTiff" - - # initiate from numpy array - if isinstance(src, np.ndarray): - if src.ndim == 2: - src = src[np.newaxis] - count, height, width = src.shape - - if in_memory is True: - memfile = MemoryFile() - dst = memfile.open( - height=height, - width=width, - count=count, - driver=driver, - dtype=src.dtype, - crs=crs, - transform=transform, - nodata=nodata, - ) - dst.write(src) - else: - with rasterio.open( - file_path, - mode="w", - driver=driver, - height=height, - width=width, - count=count, - dtype=src.dtype, - crs=crs, - transform=transform, - nodata=nodata, - ) as dst: - dst.write(src) - dst = rasterio.open(file_path, "r") - - for i in range(dst.count): - band = rasterio.band(dst, i + 1) - rasterlayer = RasterLayer(band) - if in_memory is True: - rasterlayer.in_memory = True - src_layers.append(rasterlayer) - - if tfile is not None and in_memory is False: - for layer in src_layers: - layer._close = tfile.close - self._layers = src_layers - return - - # from a single file path - elif isinstance(src, str): - src_layers = [] - r = rasterio.open(src, mode="r", driver=driver) - for i in range(r.count): - band = rasterio.band(r, i + 1) - src_layers.append(RasterLayer(band)) - self._layers = src_layers - return - - # from a single RasterLayer - elif isinstance(src, RasterLayer): - self._layers = src - self._rename_inplace(list(self.names)[0], src.name) - return - - # from a single Raster - elif isinstance(src, Raster): - self._layers = [i for i in src.values()] - for old, new in zip(self.names, list(src.names)): - self._rename_inplace(old, new) - return - - # from a single rasterio.io.datasetreader/writer - elif isinstance(src, rasterio.io.DatasetReader): - src_layers = [] - for i in range(src.count): - band = rasterio.band(src, i + 1) - src_layers.append(RasterLayer(band)) - self._layers = src_layers - return - - # from a single rasterio.band object - elif isinstance(src, rasterio.Band): - self._layers = RasterLayer(src) - return - - # from a list of objects - elif isinstance(src, list): - # list of file paths (str) - if all(isinstance(x, str) for x in src): - src_layers = [] - for f in src: - r = rasterio.open(f, mode="r", driver=driver) - for i in range(r.count): - band = rasterio.band(r, i + 1) - src_layers.append(RasterLayer(band)) - - self._layers = src_layers - return - - # list of RasterLayer objects - elif all(isinstance(x, RasterLayer) for x in src): - self._layers = src - for old, new in zip(self.names, src): - self._rename_inplace(old, new.name) - return - - # list of rasterio.io.datasetreader objects - elif all(isinstance(x, rasterio.io.DatasetReader) for x in src): - src_layers = [] - for r in src: - for i in range(r.count): - band = rasterio.band(r, i + 1) - src_layers.append(RasterLayer(band)) - self._layers = src_layers - return - - # from a list of rasterio.band objects - elif all(isinstance(x, rasterio.Band) for x in src): - src_layers = [] - for band in src: - src_layers.append(RasterLayer(band)) - self._layers = src_layers - return - else: - raise ValueError("Cannot create a Raster object from a mixture of inputs") - - @property - def block_shape(self) -> Tuple[int, int]: - """Return the block shape in (height, width) used to read windows from the - Raster - """ - return self._block_shape - - @block_shape.setter - def block_shape(self, value) -> None: - if not isinstance(value, tuple): - raise ValueError( - "block_shape must be set using an integer tuple as (rows, " "cols)" - ) - rows, cols = value - - if not isinstance(rows, int) or not isinstance(cols, int): - raise ValueError( - "tuple must consist of integer values referring to number of " - "rows, cols" - ) - self._block_shape = (rows, cols) - - def set_block_shape(self, value) -> None: - """Set the block shape of the raster, i.e. the height and width - of windows to read in chunks for the predict, predict_proba, - apply, and other supported-methods. - - Note block shape can also be set with `myraster.block_shape = (500, 500)` - - Parameters - ---------- - value : tuple - A tuple of (height, width) for the block window - """ - self.block_shape = value - - @property - def count(self) -> int: - """Return the number of layers in the Raster""" - return len(self.loc) - - @property - def crs(self) -> rasterio.crs.CRS: - """Return to crs of the Raster""" - return self.meta["crs"] - - @crs.setter - def crs(self, value) -> None: - self.meta["crs"] = value - - @property - def transform(self) -> affine.Affine: - """Return the transform of the Raster""" - return self.meta["transform"] - - @transform.setter - def transform(self, value) -> None: - self.meta["transform"] = value - - @property - def width(self) -> int: - """Return the width (number of columns) in the Raster""" - return self.meta["width"] - - @property - def height(self) -> int: - """Return the height (number of rows) in the Raster""" - return self.meta["height"] - - @property - def shape(self) -> Tuple[int, int]: - """Return the shape (height, width) of the Raster""" - return self.height, self.width - - @property - def res(self) -> Tuple[float, float]: - """Return a tuple of the resolution of the Raster in (width, height)""" - return abs(self.meta["transform"].a), abs(self.meta["transform"].e) - - @property - def bounds(self) -> namedtuple: - """Return the bounding box of the raster in (left, bottom, right, top)""" - bounds = rasterio.transform.array_bounds( - self.height, self.width, self.transform - ) - BoundingBox = namedtuple("BoundingBox", ["left", "bottom", "right", "top"]) - return BoundingBox(bounds[0], bounds[1], bounds[2], bounds[3]) - - @property - def dtypes(self) -> list: - """Return the dtype of each layer in the Raster as a list""" - dtypes = list() - - for layer in self.loc.values(): - dtypes.append(layer.dtype) - - return dtypes - - @property - def nodatavals(self) -> list: - """Return the nodata value of each layer in the Raster as a list""" - nodatavals = list() - - for layer in self.loc.values(): - try: - nodatavals.append(layer.nodata) - except: - nodatavals.append(None) - - return nodatavals - - @property - def _layers(self) -> dict: - return self.loc - - @_layers.setter - def _layers(self, layers) -> None: - """Assign RasterLayer objects to the Raster - - The function assigns the layers to the loc indexer, updates - the `files` attribute and assigns syntactically-correct names - to each layer. - - Parameters - ---------- - layers : list - A list of pyspatialml.RasterLayer objects - """ - if isinstance(layers, RasterLayer): - layers = [layers] - - if all(isinstance(x, type(layers[0])) for x in layers) is False: - raise ValueError("Cannot create a Raster object from a mixture of inputs") - - meta = self._check_alignment(layers) - - if meta is False: - raise ValueError( - "Raster datasets do not have the same dimensions/transform" - ) - - # reset locindexer - self.files = list() - for key in self.loc.keys(): - self.loc.pop(key) - - # update global Raster object attributes with new values - names = [i.name for i in layers] - names = self._fix_names(names) - - # update attributes per dataset - for layer, name in zip(layers, names): - self.files.append(layer.file) - layer.name = name - self.loc[name] = layer - - self.meta = dict( - crs=meta["crs"], - transform=meta["transform"], - width=meta["width"], - height=meta["height"], - count=self.count, - dtype=np.result_type(*self.dtypes), - ) - - @staticmethod - def _fix_names(combined_names): - """Adjusts the names of pyspatialml.RasterLayer objects within the - Raster when appending new layers. - - This avoids the Raster object containing duplicated names in the - case that multiple RasterLayers are appended with the same name. - - In the case of duplicated names, the RasterLayer names are appended - with a `_n` with n = 1, 2, 3 .. n. - - Parameters - ---------- - combined_names : list - List of str representing names of RasterLayers. Any duplicates - will have a suffix appended to them. - - Returns - ------- - list - List with adjusted names - """ - counts = Counter(combined_names) - - for s, num in counts.items(): - if num > 1: - for suffix in range(1, num + 1): - if s + "_" + str(suffix) not in combined_names: - combined_names[combined_names.index(s)] = s + "_" + str(suffix) - else: - i = 1 - while s + "_" + str(i) in combined_names: - i += 1 - combined_names[combined_names.index(s)] = s + "_" + str(i) - - return combined_names - - @staticmethod - def _check_alignment(layers): - """Check that a list of raster datasets are aligned with the same - pixel dimensions and geotransforms. - - Parameters - ---------- - layers : list - List of pyspatialml.RasterLayer objects. - - Returns - ------- - dict or False - Dict of metadata if all layers are spatially aligned, otherwise - returns False. - """ - - src_meta = [] - for layer in layers: - src_meta.append(layer.ds.meta.copy()) - - if not all(i["crs"] == src_meta[0]["crs"] for i in src_meta): - Warning("crs of all rasters does not match, possible unintended consequences") - - if not all( - [ - i["height"] == src_meta[0]["height"] - or i["width"] == src_meta[0]["width"] - or i["transform"] == src_meta[0]["transform"] - for i in src_meta - ] - ): - return False - - else: - return src_meta[0] - - def _check_supported_dtype(self, dtype=None) -> str: - """Method to check that a dtype is compatible with GDAL or - generate a compatible dtype from an array - - Parameters - ---------- - dtype : str, dtype, ndarray or None - Pass a dtype (as a string or dtype) to check compatibility. - Pass an array to generate a compatible dtype from the - array. Pass None to use the existing dtype of the parent - Raster object. - - Returns - ------- - dtype : dtype - GDAL compatible dtype - """ - if dtype is None: - dtype = self.meta["dtype"] - - elif isinstance(dtype, np.ndarray): - dtype = rasterio.dtypes.get_minimum_dtype(dtype) - - else: - if rasterio.dtypes.check_dtype(dtype) is False: - raise AttributeError( - "{dtype} is not a support GDAL dtype".format(dtype=dtype) - ) - - return dtype - - def _tempfile(self, file_path) -> Tuple[str, str]: - """Returns a TemporaryFileWrapper and file path if a file_path - parameter is None - """ - if file_path is None: - if os.name != "nt": - tfile = tempfile.NamedTemporaryFile(dir=self.tempdir, suffix=".tif") - file_path = tfile.name - else: - tfile = TempRasterLayer() - file_path = tfile.name - - else: - tfile = None - - return file_path, tfile - - def _copy(self, src, names=None): - """Return a new Raster object from a list of files but - retaining the attributes of the parent Raster. - - Designed to be used internally to copy a Raster object. - - Parameters - ---------- - src : List of RasterLayers or file paths - List of RasterLayers or file paths used create the new - Raster object. - - names : list (optional, default None) - List to name the RasterLayer objects in the stack. If not - supplied then the names will be generated from the file - names. - - Returns - ------- - pyspatialml.Raster - """ - if not isinstance(src, (list, ValuesView)): - src = [src] - - raster = Raster(src) - - # rename and copy attributes - if names is not None: - for (old, new) in zip(raster.names, names): - raster._rename_inplace(old, new) - - for old_layer, new_layer in zip(self.loc.values(), list(raster.loc.values())): - new_layer.cmap = old_layer.cmap - new_layer.norm = old_layer.norm - new_layer.categorical = old_layer.categorical - - raster.block_shape = self.block_shape - - return raster - - @staticmethod - def _apply_transformer(img, transformer): - img = np.ma.masked_invalid(img) - mask = img.mask.copy() - - # reshape into 2D array - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - flat_pixels = img.reshape((rows * cols, n_features)) - flat_pixels = flat_pixels.filled(0) - - # predict and replace mask - result = transformer.transform(flat_pixels) - - # reshape the prediction from a 1D into 3D array [band, row, col] - result = result.reshape((n_features, rows, cols)) - result = np.ma.masked_array(data=result, mask=mask, copy=True) - - return result - - def head(self) -> np.ndarray: - """Return the first 10 rows from the Raster as a ndarray""" - window = Window(col_off=0, row_off=0, width=20, height=10) - return self.read(window=window) - - def tail(self) -> np.ndarray: - """Return the last 10 rows from the Raster as a ndarray""" - window = Window( - col_off=self.width - 20, row_off=self.height - 10, width=20, height=10 - ) - return self.read(window=window) - - def close(self) -> None: - """Close all of the RasterLayer objects in the Raster. - - Note that this will cause any rasters based on temporary files - to be removed. This is intended as a method of clearing - temporary files that may have accumulated during an analysis - session. - """ - for layer in self.loc.values(): - layer.close() - - def copy(self, subset=None): - """Creates a shallow copy of a Raster object - - Note that shallow in the context of a Raster object means that - an immutable copy of the object is made, however the on-disk and - in-memory file locations remain the same. - - Parameters - ---------- - subset : opt - A list of layer names to subset while copying. - - Returns - ------- - Raster - """ - if subset is not None: - if isinstance(subset, str): - subset = [subset] - layers = list(self.loc[subset].values()) - else: - layers = list(self.loc.values()) - - return self._copy(layers) - - def block_shapes(self, rows, cols): - """Generator for windows for optimal reading and writing based - on the raster format Windows and returns as a tuple with xoff, - yoff, width, height. - - Parameters - ---------- - rows : int - Height of window in rows. - - cols : int - Width of window in columns. - """ - for i, col in enumerate(range(0, self.width, cols)): - if col + cols < self.width: - num_cols = cols - else: - num_cols = self.width - col - - for j, row in enumerate(range(0, self.height, rows)): - if row + rows < self.height: - num_rows = rows - else: - num_rows = self.height - row - - yield Window(col, row, num_cols, num_rows) - - def read( - self, - masked=False, - window=None, - out_shape=None, - resampling="nearest", - as_df=False, - **kwargs - ) -> np.ndarray: - """Reads data from the Raster object into a numpy array. - - Parameters - ---------- - masked : bool (default False) - Read data into a masked array. - - window : rasterio.window.Window object (optional, default None) - Tuple of col_off, row_off, width, height of a window of - data to read a chunk of data into a ndarray. - - out_shape : tuple (optional, default None) - Shape of shape of array (rows, cols) to read data into - using decimated reads. - - resampling : str (default 'nearest') - Resampling method to use when applying decimated reads when - out_shape is specified. Supported methods are: 'average', - 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', - 'max', 'med', 'min', 'mode', 'q1', 'q3'. - - as_df : bool (default False) - Whether to return the data as a pandas.DataFrame with - columns named by the RasterLayer names. - - **kwargs : dict - Other arguments to pass to rasterio.DatasetReader.read method - - Returns - ------- - ndarray - Raster values in 3d ndarray with the dimensions in order - of (band, row, and column). - """ - dtype = self.meta["dtype"] - - # get window to read from window or height/width of dataset - if window is None: - width = self.width - height = self.height - else: - width = window.width - height = window.height - - # decimated reads using nearest neighbor resampling - if out_shape: - height, width = out_shape - - # read bands separately into numpy array - if masked is True: - arr = np.ma.zeros((self.count, height, width), dtype=dtype) - else: - arr = np.zeros((self.count, height, width), dtype=dtype) - - for i, layer in enumerate(self.loc.values()): - arr[i, :, :] = layer.read( - masked=masked, - window=window, - out_shape=out_shape, - resampling=resampling, - **kwargs - ) - - if masked is True: - arr[i, :, :] = np.ma.MaskedArray( - data=arr[i, :, :], mask=np.isfinite(arr[i, :, :]).mask - ) - - if as_df is True: - # reshape to rows, cols, bands - arr = arr.transpose(1, 2, 0) - arr_flat = arr.reshape((arr.shape[0] * arr.shape[1], arr.shape[2])) - df = pd.DataFrame(data=arr_flat, columns=self.names) - return df - - return arr - - def write( - self, file_path, driver="GTiff", dtype=None, nodata=None, **kwargs - ): - """Write the Raster object to a file. - - Overrides the write RasterBase class method, which is a partial - function of the rasterio.DatasetReader.write method. - - Parameters - ---------- - file_path : str - File path used to save the Raster object. - - driver : str (default is 'GTiff'). - Name of GDAL driver used to save Raster data. - - dtype : str (opt, default None) - Optionally specify a numpy compatible data type when - saving to file. If not specified, a data type is selected - based on the data types of RasterLayers in the Raster - object. - - nodata : any number (opt, default None) - Optionally assign a new nodata value when saving to file. - If not specified a nodata value based on the minimum - permissible value for the data types of RasterLayers in the - Raster object is used. Note that this does not change the - pixel nodata values of the raster, it only changes the - metadata of what value represents a nodata pixel. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - New Raster object from saved file. - """ - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - meta = self.meta.copy() - meta["driver"] = driver - meta["nodata"] = nodata - meta["dtype"] = dtype - meta.update(kwargs) - - with rasterio.open(file_path, mode="w", **meta) as dst: - - for i, layer in enumerate(self.loc.values()): - arr = layer.read() - arr[arr == layer.nodata] = nodata - dst.write(arr.astype(dtype), i + 1) - - return self._copy(file_path, self.names) - - def predict_proba( - self, - estimator, - file_path=None, - in_memory=False, - indexes=None, - driver="GTiff", - dtype=None, - nodata=None, - constants=None, - progress=False, - **kwargs - ): - """Apply class probability prediction of a scikit learn model to a Raster. - - Parameters - ---------- - estimator : estimator object implementing 'fit' - The object to use to fit the data. - - file_path : str (optional, default None) - Path to a GeoTiff raster for the prediction results. If not - specified then the output is written to a temporary file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - indexes : list of integers (optional, default None) - List of class indices to export. In some circumstances, - only a subset of the class probability estimations are - desired, for instance when performing a binary - classification only the probabilities for the positive - class may be desired. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Optionally specify a GDAL compatible data type when saving - to file. If not specified, a data type is set based on the - data type of the prediction. - - nodata : any number (optional, default None) - Nodata value for file export. If not specified then the - nodata value is derived from the minimum permissible value - for the given data type. - - progress : bool (default False) - Show progress bar for prediction. - - constants: list-like object or a dict (optional, default None) - Constant features to add to the Raster object with each value - in a list or 1d ndarray representing an additional feature. - - If a list-like object of values os passed, then each numeric - value will be appended as constant features to the last - columns in the data. It is therefore important that all - features including constant features are present in the same - order as what was used to train the model. - - If a dict is passed, then the keys of the dict must refer to - the names of raster layers in the Raster object. In this case, - the values of the dict will replace the values of the raster - layers in the Raster object. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster containing predicted class probabilities. Each - predicted class is represented by a RasterLayer object. - The RasterLayers are named `prob_n` for 1,2,3..n, with `n` - based on the index position of the classes, not the number - of the class itself. - - For example, a classification model predicting classes with - integer values of 1, 3, and 5 would result in three - RasterLayers named 'prob_1', 'prob_2' and 'prob_3'. - """ - # some checks - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - # n_jobs = get_num_workers(n_jobs) - probfun = partial( - predict_prob, - estimator=estimator, - constants=constants, - names=list(self.names), - ) - - # perform test prediction - window = Window(0, 0, 1, 1) - img = self.read(masked=True, window=window) - img = np.ma.masked_invalid(img) - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - n_samples = rows * cols - flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) - flat_pixels = flat_pixels.filled(0) - - if constants is not None: - flat_pixels = stack_constants(flat_pixels, constants, list(self.names)) - - result = estimator.predict_proba(flat_pixels) - - if isinstance(indexes, int): - indexes = range(indexes, indexes + 1) - - elif indexes is None: - indexes = np.arange(0, result.shape[1]) - - # check dtype and nodata - if dtype is None: - dtype = self._check_supported_dtype(result) - else: - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - # open output file with updated metadata - meta = self.meta.copy() - count = len(indexes) - meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) - meta.update(kwargs) - - # get windows - windows = [w for w in self.block_shapes(*self.block_shape)] - data_gen = ((w, self.read(window=w, masked=True)) for w in windows) - counter = tqdm(windows, disable=not progress, total=len(windows)) - - # apply prediction function - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - for w, res, pbar in zip(windows, map(probfun, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res[indexes, :, :].astype(dtype), window=w) - - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open( - height=meta["height"], - width=meta["width"], - count=meta["count"], - dtype=meta["dtype"], - crs=meta["crs"], - transform=meta["transform"], - nodata=meta["nodata"], - driver=driver, - ) - - for w, res, pbar in zip(windows, map(probfun, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res[indexes, :, :].astype(dtype), window=w) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - - for i in output_dst: - i.in_memory = True - - # create new Raster object with the result - prefix = "prob_" - names = [prefix + str(i) for i in range(len(indexes))] - new_raster = self._copy(output_dst, names) - - # override close method - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def predict( - self, - estimator, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - progress=False, - constants=None, - **kwargs - ): - """Apply prediction of a scikit learn model to a Raster. - - The model can represent any scikit learn model or compatible - api with a `fit` and `predict` method. These can consist of - classification or regression models. Multi-class - classifications and multi-target regressions are also - supported. - - Parameters - ---------- - estimator : estimator object implementing 'fit' - The object to use to fit the data. - - file_path : str (optional, default None) - Path to a GeoTiff raster for the prediction results. If - not specified then the output is written to a temporary - file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store - the data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export - - dtype : str (optional, default None) - Optionally specify a GDAL compatible data type when saving - to file. If not specified, np.float32 is assumed. - - nodata : any number (optional, default None) - Nodata value for file export. If not specified then the - nodata value is derived from the minimum permissible value - for the given data type. - - progress : bool (default False) - Show progress bar for prediction. - - constants: list-like object or a dict (optional, default None) - Constant features to add to the Raster object with each value - in a list or 1d ndarray representing an additional feature. - - If a list-like object of values os passed, then each numeric - value will be appended as constant features to the last - columns in the data. It is therefore important that all - features including constant features are present in the same - order as what was used to train the model. - - If a dict is passed, then the keys of the dict must refer to - the names of raster layers in the Raster object. In this case, - the values of the dict will replace the values of the raster - layers in the Raster object. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster object containing prediction results as a - RasterLayers. For classification and regression models, the - Raster will contain a single RasterLayer, unless the model - is multi-class or multi-target. Layers are named - automatically as `pred_raw_n` with n = 1, 2, 3 ..n. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - # n_jobs = get_num_workers(n_jobs) - - # determine output count for multi-class or multi-target cases - window = Window(0, 0, 1, 1) - img = self.read(masked=True, window=window) - img = np.ma.masked_invalid(img) - n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] - n_samples = rows * cols - flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) - flat_pixels = flat_pixels.filled(0) - - if constants is not None: - flat_pixels = stack_constants(flat_pixels, constants, list(self.names)) - - result = estimator.predict(flat_pixels) - - if result.ndim > 1: - n_outputs = result.shape[result.ndim - 1] - else: - n_outputs = 1 - - indexes = np.arange(0, n_outputs) - - # chose prediction function - if len(indexes) == 1: - if constants is not None: - predfun = partial( - predict_output, - estimator=estimator, - constants=constants, - names=list(self.names), - ) - else: - predfun = partial( - predict_output, - estimator=estimator, - constants=constants, - names=list(self.names), - ) - else: - predfun = partial( - predict_multioutput, - estimator=estimator, - constants=constants, - names=list(self.names), - ) - - # check dtype and nodata - if dtype is None: - dtype = self._check_supported_dtype(result) - else: - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - # open output file with updated metadata - meta = self.meta.copy() - count = len(indexes) - meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) - meta.update(kwargs) - - # get windows - windows = [w for w in self.block_shapes(*self.block_shape)] - data_gen = ((w, self.read(window=w, masked=True)) for w in windows) - counter = tqdm(windows, disable=not progress, total=len(windows)) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - for w, res, pbar in zip(windows, map(predfun, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res[indexes, :, :].astype(dtype), window=w) - - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open( - height=meta["height"], - width=meta["width"], - count=meta["count"], - dtype=meta["dtype"], - crs=meta["crs"], - driver=driver, - transform=meta["transform"], - nodata=meta["nodata"], - ) - - for w, res, pbar in zip(windows, map(predfun, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res[indexes, :, :].astype(dtype), window=w) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - - for i in output_dst: - i.in_memory = True - - # create new Raster object with the result - prefix = "pred_raw_" - names = [prefix + str(i) for i in range(len(indexes))] - new_raster = self._copy(output_dst, names) - - # override close method - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def append(self, other, in_place=False): - """Method to add new RasterLayers to a Raster object. - - Note that this modifies the Raster object in-place by default. - - Parameters - ---------- - other : Raster object, or list of Raster objects - Object to append to the Raster. - - in_place : bool (default False) - Whether to change the Raster object in-place or leave - original and return a new Raster object. - - Returns - ------- - Raster - Returned only if `in_place` is False - """ - if isinstance(other, Raster): - other = [other] - - combined_names = self.names - combined_layers = list(self.loc.values()) - - for new_raster in other: - if not isinstance(new_raster, Raster): - raise AttributeError(new_raster + " is not a pyspatialml.Raster object") - - # check that other raster does not result in duplicated names - combined_names = list(combined_names) + list(new_raster.names) - combined_names = self._fix_names(combined_names) - - # update layers and names - combined_layers = combined_layers + list(new_raster.loc.values()) - - for layer, name in zip(combined_layers, combined_names): - layer.names = [name] - - if in_place is True: - self._layers = combined_layers - self.names = combined_names - else: - new_raster = self._copy(self.files, self.names) - new_raster._layers = combined_layers - return new_raster - - def drop(self, labels, in_place=False): - """Drop individual RasterLayers from a Raster object - - Note that this modifies the Raster object in-place by default. - - Parameters - --------- - labels : single label or list-like - Index (int) or layer name to drop. Can be a single integer - or label, or a list of integers or labels. - - in_place : bool (default False) - Whether to change the Raster object in-place or leave - original and return a new Raster object. - - Returns - ------- - pyspatialml.Raster - Returned only if `in_place` is True - """ - # convert single label to list - if isinstance(labels, (str, int)): - labels = [labels] - - # numerical index based subsetting - if len([i for i in labels if isinstance(i, int)]) == len(labels): - subset_layers = [ - v for (i, v) in enumerate(list(self.loc.values())) if i not in labels - ] - - # str label based subsetting - elif len([i for i in labels if isinstance(i, str)]) == len(labels): - subset_layers = [ - v - for (i, v) in enumerate(list(self.loc.values())) - if list(self.names)[i] not in labels - ] - - else: - raise ValueError( - "Cannot drop layers based on mixture of indexes and labels" - ) - - if in_place is True: - self._layers = subset_layers - else: - new_raster = self._copy(self.files, self.names) - new_raster._layers = subset_layers - - return new_raster - - def rename(self, names, in_place=False): - """Rename a RasterLayer within the Raster object. - - Parameters - ---------- - names : dict - dict of old_name : new_name - - in_place : bool (default False) - Whether to change names of the Raster object in-place or - leave original and return a new Raster object. - - Returns - ------- - pyspatialml.Raster - Returned only if `in_place` is False - """ - if in_place is True: - for old_name, new_name in names.items(): - self._rename_inplace(old_name, new_name) - else: - new_raster = self._copy(src=[v for (_, v) in self.items()]) - - for old_name, new_name in names.items(): - new_raster._rename_inplace(old_name, new_name) - - return new_raster - - def mask( - self, - shapes, - invert=False, - crop=True, - pad=False, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - **kwargs - ): - """Mask a Raster object based on the outline of shapes in a - geopandas.GeoDataFrame - - Parameters - ---------- - shapes : geopandas.GeoDataFrame - GeoDataFrame containing masking features. - - invert : bool (default False) - If False then pixels outside shapes will be masked. If True - then pixels inside shape will be masked. - - crop : bool (default True) - Crop the raster to the extent of the shapes. - - pad : bool (default False) - If True, the features will be padded in each direction by - one half of a pixel prior to cropping raster. - - file_path : str (optional, default None) - File path to save to resulting Raster. If not supplied - then the resulting Raster is saved to a temporary file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store - the data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Coerce RasterLayers to the specified dtype. If not - specified then the cropped Raster is created using the - existing dtype, which usesa dtype that can accommodate the - data types of all of the individual RasterLayers. - - nodata : any number (optional, default None) - Nodata value for cropped dataset. If not specified then a - nodata value is set based on the minimum permissible value - of the Raster's data type. Note that this changes the - values of the pixels to the new nodata value, and changes - the metadata of the raster. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - pyspatialml.Raster - Raster with masked layers. - """ - # some checks - if invert is True: - crop = False - - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - meta = self.meta.copy() - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - meta["dtype"] = dtype - - masked_ndarrays = [] - - for layer in self.loc.values(): - # set pixels outside of mask to raster band's nodata value - masked_arr, transform = rasterio.mask.mask( - dataset=layer.ds, - shapes=[shapes.geometry.unary_union], - filled=False, - invert=invert, - crop=crop, - pad=pad, - ) - - if layer.ds.count > 1: - masked_arr = masked_arr[layer.bidx - 1, :, :] - - else: - masked_arr = np.ma.squeeze(masked_arr) - - masked_ndarrays.append(masked_arr) - - # stack list of 2d arrays into 3d array - masked_ndarrays = np.ma.stack(masked_ndarrays) - - # write to file - meta["transform"] = transform - meta["driver"] = driver - meta["nodata"] = nodata - meta["height"] = masked_ndarrays.shape[1] - meta["width"] = masked_ndarrays.shape[2] - meta.update(kwargs) - masked_ndarrays = masked_ndarrays.filled(fill_value=nodata) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(masked_ndarrays.astype(dtype)) - output_dst = file_path - else: - with MemoryFile() as memfile: - dst = memfile.open(**meta) - dst.write(masked_ndarrays.astype(dtype)) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - for i in output_dst: - i.in_memory = True - - # create new Raster object with the result - new_raster = self._copy(output_dst, self.names) - - # override close method - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def intersect( - self, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - **kwargs - ): - """Perform a intersect operation on the Raster object. - - Computes the geometric intersection of the RasterLayers with - the Raster object. This will cause nodata values in any of - the rasters to be propagated through all of the output rasters. - - Parameters - ---------- - file_path : str (optional, default None) - File path to save to resulting Raster. If not supplied then - the resulting Raster is saved to a temporary file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Coerce RasterLayers to the specified dtype. If not - specified then the new intersected Raster is created using - the dtype of the existing Raster dataset, which uses a - dtype that can accommodate the data types of all of the - individual RasterLayers. - - nodata : any number (optional, default None) - Nodata value for new dataset. If not specified then a - nodata value is set based on the minimum permissible value - of the Raster's data type. Note that this changes the - values of the pixels that represent nodata to the new - value. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster with layers that are masked based on a union of all - masks in the suite of RasterLayers. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - meta = self.meta.copy() - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - arr = self.read(masked=True) - mask_2d = arr.mask.any(axis=0) - - # repeat mask for n_bands - mask_3d = np.repeat(a=mask_2d[np.newaxis, :, :], repeats=self.count, axis=0) - - intersected_arr = np.ma.masked_array(arr, mask=mask_3d, fill_value=nodata) - intersected_arr = np.ma.filled(intersected_arr, fill_value=nodata) - - meta["driver"] = driver - meta["nodata"] = nodata - meta["dtype"] = dtype - meta.update(kwargs) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(intersected_arr.astype(dtype)) - output_dst = file_path - else: - with MemoryFile() as memfile: - dst = memfile.open(**meta) - dst.write(intersected_arr.astype(dtype)) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - for i in output_dst: - i.in_memory = True - - # create new Raster object with the result - new_raster = self._copy(output_dst, self.names) - - # override close method - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def crop( - self, - bounds, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - **kwargs - ): - """Crops a Raster object by the supplied bounds. - - Parameters - ---------- - bounds : tuple - A tuple containing the bounding box to clip by in the form - of (xmin, ymin, xmax, ymax). - - file_path : str (optional, default None) - File path to save to cropped raster. If not supplied then - the cropped raster is saved to a temporary file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store - the data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff'). Default is 'GTiff' - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Coerce RasterLayers to the specified dtype. If not - specified then the new intersected Raster is created using - the dtype of theexisting Raster dataset, which uses a - dtype that can accommodate the data types of all of the - individual RasterLayers. - - nodata : any number (optional, default None) - Nodata value for new dataset. If not specified then a - nodata value is set based on the minimum permissible value - of the Raster's data type. Note that this does not change - the pixel nodata values of the raster, it only changes - the metadata of what value represents a nodata pixel. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster cropped to new extent. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - dtype = self._check_supported_dtype(dtype) - if nodata is None: - nodata = get_nodata_value(dtype) - - # get row, col positions for bounds - xmin, ymin, xmax, ymax = bounds - rows, cols = rasterio.transform.rowcol( - transform=self.transform, xs=(xmin, xmax), ys=(ymin, ymax) - ) - - # create window covering the min/max rows and cols - window = Window( - col_off=min(cols), - row_off=min(rows), - width=max(cols) - min(cols), - height=max(rows) - min(rows), - ) - cropped_arr = self.read(masked=True, window=window) - - # calculate the new transform - new_transform = rasterio.transform.from_bounds( - west=xmin, - south=ymin, - east=xmax, - north=ymax, - width=cropped_arr.shape[2], - height=cropped_arr.shape[1], - ) - - # update the destination meta - meta = self.meta.copy() - meta.update( - transform=new_transform, - width=cropped_arr.shape[2], - height=cropped_arr.shape[1], - driver=driver, - nodata=nodata, - dtype=dtype, - ) - meta.update(kwargs) - cropped_arr = cropped_arr.filled(fill_value=nodata) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(cropped_arr.astype(dtype)) - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open(**meta) - dst.write(cropped_arr.astype(dtype)) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - for i in output_dst: - i.in_memory = True - - new_raster = self._copy(output_dst, self.names) - - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def to_crs( - self, - crs, - resampling="nearest", - file_path=None, - in_memory=False, - driver="GTiff", - nodata=None, - n_jobs=1, - warp_mem_lim=0, - progress=False, - **kwargs - ): - """Reprojects a Raster object to a different crs. - - Parameters - ---------- - crs : rasterio.transform.CRS object, or dict - Example: CRS({'init': 'EPSG:4326'}) - - resampling : str (default 'nearest') - Resampling method to use. One of the following: - nearest, - bilinear, - cubic, - cubic_spline, - lanczos, - average, - mode, - max (GDAL >= 2.2), - min (GDAL >= 2.2), - med (GDAL >= 2.2), - q1 (GDAL >= 2.2), - q3 (GDAL >= 2.2) - - file_path : str (optional, default None) - Optional path to save reprojected Raster object. If not - specified then a tempfile is used. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - nodata : any number (optional, default None) - Nodata value for new dataset. If not specified then the - existing nodata value of the Raster object is used, which - can accommodate the dtypes of the individual layers in the - Raster. - - n_jobs : int (default 1) - The number of warp worker threads. - - warp_mem_lim : int (default 0) - The warp operation memory limit in MB. Larger values allow - the warp operation to be carried out in fewer chunks. The - amount of memory required to warp a 3-band uint8 2000 row - x 2000 col raster to a destination of the same size is - approximately 56 MB. The default (0) means 64 MB with GDAL - 2.2. - - progress : bool (default False) - Optionally show progress of transform operations. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster following reprojection. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - if nodata is None: - nodata = get_nodata_value(self.meta["dtype"]) - - resampling_methods = [i.name for i in rasterio.enums.Resampling] - if resampling not in resampling_methods: - raise ValueError( - "Resampling method must be one of {}:".format(resampling_methods) - ) - - dst_transform, dst_width, dst_height = calculate_default_transform( - src_crs=self.crs, - dst_crs=crs, - width=self.width, - height=self.height, - left=self.bounds.left, - right=self.bounds.right, - bottom=self.bounds.bottom, - top=self.bounds.top, - ) - - meta = self.meta.copy() - meta["nodata"] = nodata - meta["width"] = dst_width - meta["height"] = dst_height - meta["transform"] = dst_transform - meta["crs"] = crs - meta.update(kwargs) - - if progress is True: - t = tqdm(total=self.count) - - if in_memory is False: - with rasterio.open(file_path, "w", driver=driver, **meta) as dst: - for i, layer in enumerate(self.loc.values()): - reproject( - source=rasterio.band(layer.ds, layer.bidx), - destination=rasterio.band(dst, i + 1), - resampling=rasterio.enums.Resampling[resampling], - num_threads=n_jobs, - warp_mem_lim=warp_mem_lim, - ) - - if progress is True: - t.update() - - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open(driver=driver, **meta) - for i, layer in enumerate(self.loc.values()): - reproject( - source=rasterio.band(layer.ds, layer.bidx), - destination=rasterio.band(dst, i + 1), - resampling=rasterio.enums.Resampling[resampling], - num_threads=n_jobs, - warp_mem_lim=warp_mem_lim, - ) - - if progress is True: - t.update() - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - - for i in output_dst: - i.in_memory = True - - new_raster = self._copy(output_dst, self.names) - - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def aggregate( - self, - out_shape, - resampling="nearest", - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - **kwargs - ): - """Aggregates a raster to (usually) a coarser grid cell size. - - Parameters - ---------- - out_shape : tuple - New shape in (rows, cols). - - resampling : str (default 'nearest') - Resampling method to use when applying decimated reads when - out_shape is specified. Supported methods are: 'average', - 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', - 'max', 'med', 'min', 'mode', 'q1', 'q3'. - - file_path : str (optional, default None) - File path to save to cropped raster. If not supplied then - the aggregated raster is saved to a temporary file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store - the data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Coerce RasterLayers to the specified dtype. If not - specified then the new intersected Raster is created using - the dtype of the existing Raster dataset, which uses a - dtype that can accommodate the data types of all of the - individual RasterLayers. - - nodata : any number (optional, default None) - Nodata value for new dataset. If not specified then a - nodata value is set based on the minimum permissible value - of the Raster's dtype. Note that this does not change the - pixel nodata values of the raster, it only changes the - metadata of what value represents a nodata pixel. - - kwargs : opt - Optional named arguments to pass to the format drivers. For - example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster object aggregated to a new pixel size. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - rows, cols = out_shape - arr = self.read(masked=True, out_shape=out_shape, resampling=resampling) - meta = self.meta.copy() - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - arr = arr.filled(fill_value=nodata) - - meta["driver"] = driver - meta["nodata"] = nodata - meta["height"] = rows - meta["width"] = cols - meta["dtype"] = dtype - bnd = self.bounds - meta["transform"] = rasterio.transform.from_bounds( - west=bnd.left, - south=bnd.bottom, - east=bnd.right, - north=bnd.top, - width=cols, - height=rows, - ) - meta.update(kwargs) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - dst.write(arr.astype(dtype)) - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open(**meta) - dst.write(arr.astype(dtype)) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - for i in output_dst: - i.in_memory = True - - new_raster = self._copy(output_dst, self.names) - - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def apply( - self, - function, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - progress=False, - function_args={}, - **kwargs - ): - """Apply user-supplied function to a Raster object. - - Parameters - ---------- - function : function - Function that takes an numpy array as a single argument. - - file_path : str (optional, default None) - Optional path to save calculated Raster object. If not - specified then a tempfile is used. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Coerce RasterLayers to the specified dtype. If not - specified then the new Raster is created using the dtype of - the calculation result. - - nodata : any number (optional, default None) - Nodata value for new dataset. If not specified then a - nodata value is set based on the minimum permissible value - of the Raster's data type. Note that this changes the - values of the pixels that represent nodata pixels. - - progress : bool (default False) - Optionally show progress of transform operations. - - function_args : dict (optional) - Optionally pass arguments to the `function` as a dict or - keyword arguments. - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - Raster - Raster containing the calculated result. - """ - tfile = None - - if in_memory is False: - file_path, tfile = self._tempfile(file_path) - - function = partial(function, **function_args) - - # perform test calculation determine dimensions, dtype, nodata - window = next(self.block_shapes(*self.block_shape)) - img = self.read(masked=True, window=window) - arr = function(img, **function_args) - - if arr.ndim > 2: - indexes = np.arange(1, arr.shape[0] + 1) - count = len(indexes) - else: - indexes = 1 - count = 1 - - dtype = self._check_supported_dtype(dtype) - - if nodata is None: - nodata = get_nodata_value(dtype) - - # open output file with updated metadata - meta = self.meta.copy() - meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) - meta.update(kwargs) - - # get windows - windows = [w for w in self.block_shapes(*self.block_shape)] - data_gen = (self.read(window=w, masked=True) for w in windows) - counter = tqdm(windows, total=len(windows), disable=not progress) - - if in_memory is False: - with rasterio.open(file_path, "w", **meta) as dst: - for w, res, pbar in zip(windows, map(function, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res.astype(dtype), window=w, indexes=indexes) - - output_dst = file_path - - else: - with MemoryFile() as memfile: - dst = memfile.open(**meta) - for w, res, pbar in zip(windows, map(function, data_gen), counter): - res = np.ma.filled(res, fill_value=nodata) - dst.write(res.astype(dtype), window=w, indexes=indexes) - - output_dst = [ - RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) - ] - - for i in output_dst: - i.in_memory = True - - # create new raster object with result - new_raster = self._copy(output_dst) - - # override close method - if tfile is not None: - for layer in new_raster.iloc: - layer._close = tfile.close - - return new_raster - - def to_pandas(self, max_pixels=None, resampling="nearest") -> pd.DataFrame: - """Raster to pandas DataFrame. - - Parameters - ---------- - max_pixels: int (default None) - Maximum number of pixels to sample. By default all pixels - are used. - - resampling : str (default 'nearest') - Resampling method to use when applying decimated reads when - out_shape is specified. Supported methods are: 'average', - 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', - 'max', 'med', 'min', 'mode', 'q1', 'q3'. - - Returns - ------- - pandas.DataFrame - DataFrame containing values of names of RasterLayers in - the Raster as columns, and pixel values as rows. - """ - - # read dataset using decimated reads - if max_pixels is not None: - rel_width = self.shape[1] / max_pixels - - if rel_width > 1: - col_scaling = round(max_pixels / rel_width) - row_scaling = max_pixels - col_scaling - else: - col_scaling = round(max_pixels * rel_width) - row_scaling = max_pixels - col_scaling - else: - row_scaling, col_scaling = self.shape[0], self.shape[1] - - out_shape = (row_scaling, col_scaling) - arr = self.read(masked=True, out_shape=out_shape, resampling=resampling) - bands, rows, cols = arr.shape - nodatavals = self.nodatavals - - # x and y grid coordinate arrays - x_range = np.linspace(start=self.bounds.left, stop=self.bounds.right, num=cols) - y_range = np.linspace(start=self.bounds.top, stop=self.bounds.bottom, num=rows) - xs, ys = np.meshgrid(x_range, y_range) - - arr = arr.reshape((bands, rows * cols)) - arr = arr.transpose() - df = pd.DataFrame( - data=np.column_stack((xs.flatten(), ys.flatten(), arr)), - columns=["x", "y"] + list(self.names), - ) - - # set nodata values to nan - for i, col_name in enumerate(self.names): - df.loc[df[col_name] == nodatavals[i], col_name] = np.nan - - return df - - def sample(self, size, strata=None, return_array=False, random_state=None): - """Generates a random sample of according to size, and samples - the pixel values. - - Parameters - ---------- - size : int - Number of random samples or number of samples per strata if - a `strata` object is supplied. - - strata : pyspatialml Raster object (opt) - Whether to use stratified instead of random sampling. Strata - can be supplied using another pyspatialml.Raster object. - - return_array : bool (opt), default=False - Optionally return extracted data as separate X and xy - masked numpy arrays. - - random_state : int (opt) - integer to use within random.seed. - - Returns - ------- - pandas.DataFrame - DataFrame containing values of names of RasterLayers in the Raster - if `return_array` is False. - - tuple - A tuple containing two elements if `return_array` is True: - - - numpy.ndarray - Numpy array of extracted raster values, typically 2d. - - numpy.ndarray - 2D numpy array of xy coordinates of extracted values. - """ - # set the seed - np.random.seed(seed=random_state) - - if not strata: - # create np array to store randomly sampled data - valid_samples = np.zeros((0, self.count)) - valid_coordinates = np.zeros((0, 2)) - - # loop until target number of samples is satisfied - satisfied = False - - n = size - while satisfied is False: - - # generate random row and column indices - Xsample = np.random.choice(range(0, self.width), n) - Ysample = np.random.choice(range(0, self.height), n) - - # create 2d numpy array with sample locations set to 1 - sample_raster = np.empty((self.height, self.width)) - sample_raster[:] = np.nan - sample_raster[Ysample, Xsample] = 1 - - # get indices of sample locations - rows, cols = np.nonzero(np.isnan(sample_raster) == False) - - # convert row, col indices to coordinates - xy = np.transpose(rasterio.transform.xy(self.transform, rows, cols)) - - # sample at random point locations - samples = self.extract_xy_chunked(xs=xy[:, 0], ys=xy[:, 1]) - - # append only non-masked data to each row of X_random - samples = samples.astype("float32").filled(np.nan) - invalid_ind = np.isnan(samples).any(axis=1) - samples = samples[~invalid_ind, :] - valid_samples = np.append(valid_samples, samples, axis=0) - - xy = xy[~invalid_ind, :] - valid_coordinates = np.append(valid_coordinates, xy, axis=0) - - # check to see if target_nsamples has been reached - if len(valid_samples) >= size: - satisfied = True - else: - n = size - len(valid_samples) - - else: - if strata.count != 1: - raise AttributeError( - "Strata must be a Raster object with a single band." - ) - - # get number of unique categories - strata_arr = strata.iloc[0].read(masked=True) - categories = np.unique(strata_arr.flatten()) - categories = categories[~categories.mask] - - # store selected coordinates - selected = np.zeros((0, 2)) - - for cat in categories: - - # get row,col positions for cat strata - ind = np.transpose(np.nonzero(strata_arr == cat)) - - if size > ind.shape[0]: - msg = ( - "Sample size is greater than number of pixels in " "strata {}" - ).format(str(ind)) - - msg = os.linesep.join([msg, "Sampling using replacement"]) - Warning(msg) - - # random sample - sample = np.random.uniform(0, ind.shape[0], size).astype("int") - xy = ind[sample, :] - - selected = np.append(selected, xy, axis=0) - - # convert row, col indices to coordinates - x, y = rasterio.transform.xy( - transform=self.transform, rows=selected[:, 0], cols=selected[:, 1] - ) - valid_coordinates = np.column_stack((x, y)) - - # extract data - valid_samples = self.extract_xy_chunked( - xs=valid_coordinates[:, 0], ys=valid_coordinates[:, 1] - ) - - # return as geopandas array as default (or numpy arrays) - if return_array is False: - gdf = pd.DataFrame(valid_samples, columns=self.names) - gdf["geometry"] = list( - zip(valid_coordinates[:, 0], valid_coordinates[:, 1]) - ) - gdf["geometry"] = gdf["geometry"].apply(Point) - gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) - return gdf - else: - return valid_samples, valid_coordinates - - def extract_xy(self, xys, return_array=False, progress=False): - """Samples pixel values using an array of xy locations. - - Parameters - ---------- - xys : 2d array-like - x and y coordinates from which to sample the raster - (n_samples, xys). - - return_array : bool (opt), default=False - By default the extracted pixel values are returned as a - geopandas.GeoDataFrame. If `return_array=True` then the - extracted pixel values are returned as a tuple of - numpy.ndarrays. - - progress : bool (opt), default=False - Show a progress bar for extraction. - - Returns - ------- - geopandas.GeoDataframe - Containing extracted data as point geometries if - `return_array=False`. - - numpy.ndarray - 2d masked array containing sampled raster values (sample, - bands) at the x,y locations. - """ - # extract pixel values - dtype = np.find_common_type([np.float32], self.dtypes) - X = np.ma.zeros((xys.shape[0], self.count), dtype=dtype) - t = tqdm(self.loc.values(), total=self.count, disable=not progress) - - for i, (layer, pbar) in enumerate(zip(self.loc.values(), t)): - sampler = sample_gen( - dataset=layer.ds, xy=xys, indexes=layer.bidx, masked=True - ) - v = np.ma.asarray([i for i in sampler]) - X[:, i] = v.flatten() - - # return as geopandas array as default (or numpy arrays) - if return_array is False: - gdf = pd.DataFrame(X, columns=self.names) - gdf["geometry"] = list(zip(xys[:, 0], xys[:, 1])) - gdf["geometry"] = gdf["geometry"].apply(Point) - gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) - return gdf - - return X - - def extract_xy_chunked(self, xs, ys, progress=False): - rows, cols = rowcol(self.transform, xs, ys) - rowcol_idx = np.column_stack((rows, cols)) - pixel_index = np.arange(rowcol_idx.shape[0]) - - # get row, col positions that are outside of the raster - negative_idx = (rowcol_idx < 0).any(axis=1) - outside_idx = (rowcol_idx[:, 0] >= self.shape[0]) | ( - rowcol_idx[:, 1] >= self.shape[1] - ) - - outsiders = np.logical_or(negative_idx, outside_idx) - valid = np.nonzero(outsiders == False)[0] - invalid = np.nonzero(outsiders == True)[0] - - # remove row, col > shape - rowcol_idx = rowcol_idx[~outsiders, :] - pixel_index = pixel_index[~outsiders] - - # lookup pixel values at row, col positons by chunk - windows = [w for w in self.block_shapes(*self.block_shape)] - data_gen = (self.read(window=w, masked=True) for w in windows) - t = tqdm(windows, total=len(windows), disable=not progress) - - dtype = np.result_type(np.float32, *self.dtypes) - X = np.ma.zeros((self.count, 0), dtype=dtype) - pixel_indices = np.zeros(0, dtype="int") - - for w, data, pbar in zip(windows, data_gen, t): - res, chunk_pixels = self.extract_by_chunk(data, w, rowcol_idx, pixel_index) - X = np.ma.concatenate((X, res), axis=1) - pixel_indices = np.concatenate((pixel_indices, chunk_pixels)) - - X = X.transpose((1, 0)) - - # insert empty rows to make input dimensions match output - output_arr = np.ma.zeros((len(rows), self.count)) - output_arr[pixel_indices, :] = X - output_arr[invalid, :].mask = True - output_arr[invalid, :] = None - - return output_arr - - def extract_vector(self, gdf, progress=False): - """Sample a Raster/RasterLayer using a geopandas GeoDataframe - containing points, lines or polygon features. - - Parameters - ---------- - gdf: geopandas.GeoDataFrame - Containing either point, line or polygon geometries. - Overlapping geometries will cause the same pixels to be - sampled. - - progress : bool (opt), default=False - Show a progress bar for extraction. - - Returns - ------- - geopandas.GeoDataframe - Containing extracted data as point geometries (one point - per pixel). The resulting GeoDataFrame is indexed using - a named pandas.MultiIndex, with `pixel_idx` index - referring to the index of each pixel that was sampled, and - the `geometry_idx` index referring to the index of the each - geometry in the supplied `gdf`. This makes it possible to - keep track of how sampled pixel relates to the original - geometries, i.e. multiple pixels being extracted within - the area of a single polygon that can be referred to using - the `geometry_idx`. - - The extracted data can subsequently be joined with the - attribute table of the supplied `gdf` using: - - training_py = geopandas.read_file(nc.polygons) - df = self.stack.extract_vector(gdf=training_py) - df = df.dropna() - - df = df.merge( - right=training_py.loc[:, ("id", "label")], - left_on="polygon_idx", - right_on="id", - right_index=True - ) - """ - # rasterize polygon and line geometries - if all(gdf.geom_type == "Polygon") or all(gdf.geom_type == "LineString"): - - shapes = [(geom, val) for geom, val in zip(gdf.geometry, gdf.index)] - arr = np.ma.zeros((self.height, self.width)) - arr[:] = -99999 - - arr = features.rasterize( - shapes=shapes, - fill=-99999, - out=arr, - transform=self.transform, - all_touched=True, - ) - - ids = arr[np.nonzero(arr != -99999)] - ids = ids.astype("int") - rows, cols = np.nonzero(arr != -99999) - xys = rasterio.transform.xy(transform=self.transform, rows=rows, cols=cols) - xys = np.transpose(xys) - - elif all(gdf.geom_type == "Point"): - ids = gdf.index.values - xys = gdf.bounds.iloc[:, 2:].values - - # extract raster pixels - X = self.extract_xy_chunked(xs=xys[:, 0], ys=xys[:, 1], progress=progress) - - # return as geopandas array as default (or numpy arrays) - X = pd.DataFrame( - data=X, columns=list(self.names), index=[pd.RangeIndex(0, X.shape[0]), ids] - ) - X.index.set_names(["pixel_idx", "geometry_idx"], inplace=True) - X["geometry"] = list(zip(xys[:, 0], xys[:, 1])) - X["geometry"] = X["geometry"].apply(Point) - X = gpd.GeoDataFrame(X, geometry="geometry", crs=self.crs) - - return X - - def extract_raster(self, src, progress=False): - """Sample a Raster object by an aligned raster of labelled pixels. - - Parameters - ---------- - src: rasterio DatasetReader - Single band raster containing labelled pixels as an open - rasterio DatasetReader object. - - progress : bool (opt), default=False - Show a progress bar for extraction. - - Returns - ------- - geopandas.GeoDataFrame - Geodataframe containing extracted data as point features if - `return_array=False` - """ - # open response raster and get labelled pixel indices and values - arr = src.read(1, masked=True) - rows, cols = np.nonzero(~arr.mask) - xys = np.transpose(rasterio.transform.xy(src.transform, rows, cols)) - ys = arr.data[rows, cols] - - # extract Raster object values at row, col indices - X = self.extract_xy_chunked(xs=xys[:, 0], ys=xys[:, 1], progress=progress) - - # summarize data - column_names = ["value"] + list(self.names) - gdf = pd.DataFrame(data=np.ma.column_stack((ys, X)), columns=column_names) - gdf["geometry"] = list(zip(xys[:, 0], xys[:, 1])) - gdf["geometry"] = gdf["geometry"].apply(Point) - gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) - - return gdf - - @staticmethod - def extract_by_chunk(arr, w, idx, pixel_idx): - d = idx.copy() - pixel_idx = pixel_idx.copy() - - # subtract chunk offset from row, col positions - d[:, 0] = d[:, 0] - w.row_off - d[:, 1] = d[:, 1] - w.col_off - - # remove negative row, col positions - pos = (d >= 0).all(axis=1) - d = d[pos, :] - pixel_idx = pixel_idx[pos] - - # remove row, col > shape - within_range = (d[:, 0] < arr.shape[1]) & (d[:, 1] < arr.shape[2]) - d = d[within_range, :] - pixel_idx = pixel_idx[within_range] - - extracted_data = arr[:, d[:, 0], d[:, 1]] - return (extracted_data, pixel_idx) - - def scale( - self, - centre=True, - scale=True, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - progress=False, - ): - """Standardize (centre and scale) a Raster object by - subtracting the mean and dividing by the standard deviation for - each layer in the object. - - The mean and standard deviation statistics are calculated - for each layer separately. - - Parameters - ---------- - centre : bool, default is True - Whether to subtract the mean from each layer. - - scale : bool, default is True - Whether to divide each layer by the standard deviation of - the layer. - - file_path : str (optional, default None) - Path to a GeoTiff raster for the prediction results. If - not specified then the output is written to a temporary - file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Optionally specify a GDAL compatible data type when saving - to file. If not specified, a data type is set based on the - data type of the prediction. - - nodata : any number (optional, default None) - Nodata value for file export. If not specified then the - nodata value is derived from the minimum permissible value - for the given data type. - - progress : bool (default False) - Show progress bar for operation. - - Returns - ------- - Pyspatialml.Raster object with rescaled data. - """ - - def scaler(x, means, sds): - for i, m, z in zip(range(x.shape[0]), means, sds): - x[i, :, :] = (x[i, :, :] - m) / z - return x - - if centre is True: - means = self.mean() - else: - means = np.repeat(0, self.count) - - if scale is True: - sds = self.stddev() - else: - sds = np.repeat(1, self.count) - - res = self.apply( - scaler, - file_path=file_path, - in_memory=in_memory, - driver=driver, - dtype=dtype, - nodata=nodata, - progress=progress, - function_args=dict(means=means, sds=sds), - ) - - return res - - def alter( - self, - transformer, - file_path=None, - in_memory=False, - driver="GTiff", - dtype=None, - nodata=None, - progress=False, - ): - """Apply a fitted scikit-learn transformer to a Raster object. - - Can be used to transform a raster using methods such as StandardScaler, - RobustScaler etc. - - Parameters - ---------- - transformer : a sklearn.preprocessing.Transformer object - - file_path : str (optional, default None) - Path to a GeoTiff raster for the prediction results. If - not specified then the output is written to a temporary - file. - - in_memory : bool, default is False - Whether to initiated the Raster from an array and store the - data in-memory using Rasterio's in-memory files. - - driver : str (default 'GTiff') - Named of GDAL-supported driver for file export. - - dtype : str (optional, default None) - Optionally specify a GDAL compatible data type when saving - to file. If not specified, a data type is set based on the - data type of the prediction. - - nodata : any number (optional, default None) - Nodata value for file export. If not specified then the - nodata value is derived from the minimum permissible value - for the given data type. - - progress : bool (default False) - Show progress bar for operation. - - Returns - ------- - Pyspatialml.Raster object with transformed data. - """ - res = self.apply( - self._apply_transformer, - file_path=file_path, - in_memory=in_memory, - driver=driver, - dtype=dtype, - nodata=nodata, - progress=progress, - function_args={"transformer": transformer}, - ) - - return res - - -class TempRasterLayer: - """Create a NamedTemporaryFile like object on Windows that has a - close method - - Workaround used on Windows which cannot open the file a second time - """ - - def __init__(self, tempdir=tempfile.tempdir): - self.tfile = tempfile.NamedTemporaryFile(dir=tempdir, suffix=".tif").name - self.name = self.tfile - - def close(self): - os.unlink(self.tfile) +import os +import tempfile +from collections import namedtuple +from collections.abc import ValuesView +from functools import partial +from typing import Tuple +import affine + +import geopandas as gpd +import numpy as np +import pandas as pd +import rasterio +import rasterio.mask +import rasterio.plot +from rasterio import features +from rasterio.io import MemoryFile +from rasterio.sample import sample_gen +from rasterio.warp import calculate_default_transform, reproject +from rasterio.windows import Window +from rasterio.transform import rowcol +from shapely.geometry import Point +from tqdm import tqdm +from collections import Counter + +from ._plotting import RasterPlotMixin +from ._prediction import ( + predict_multioutput, + predict_output, + predict_prob, + stack_constants, +) +from ._utils import get_nodata_value +from .rasterlayer import RasterLayer +from ._rasterstats import RasterStatsMixin +from .locindexer import _LocIndexer + + +class Raster(_LocIndexer, RasterStatsMixin, RasterPlotMixin): + """Creates a collection of file-based GDAL-supported raster + datasets that share a common coordinate reference system and + geometry. + + Raster objects encapsulate RasterLayer objects, which represent + single band raster datasets that can physically be represented by + either separate single-band raster files, multi-band raster files, + or any combination of individual bands from multi-band raster and + single-band raster datasets. + + Attributes + ---------- + files : list + A list of the raster dataset files that are used in the Raster. + This does not have to be the same length as the number of + RasterLayers because some files may have multiple bands. + + meta : dict + A dict containing the raster metadata. The dict contains the + following keys/values: + + crs : the crs object + transform : the Affine.affine transform object + width : width of the Raster in pixels + height : height of the Raster in pixels + count : number of RasterLayers within the Raster + dtype : the numpy datatype that represents lowest common + denominator of the different dtypes for all of the layers + in the Raster. + + names : list + A list of the RasterLayer names. + + block_shape : tuple + The default block_shape in (rows, cols) for reading windows of data + in the Raster for out-of-memory processing. + """ + + def __init__( + self, + src, + crs=None, + transform=None, + nodata=None, + file_path=None, + driver=None, + tempdir=tempfile.tempdir, + in_memory=False, + ): + """Initiate a new Raster object + + Parameters + ---------- + src : file path, RasterLayer, rasterio dataset, or a ndarray + Initiate a Raster object from any combination of a file + path or list of file paths to GDAL-supported raster + datasets, RasterLayer objects, or directly from a rasterio + dataset or band object that is opened in 'r' or 'rw' mode. + + A Raster object can also be created directly from a numpy + array in [band, rows, cols] order. The additional arguments + `crs` and `transform` should also be provided to supply + spatial coordinate information. + + crs : rasterio.crs.CRS object (optional, default is None) + CRS object containing projection information for data if + provided as an array. + + transform : affine.Affine object (optional, default is None) + Affine object containing transform information for data if + provided as an array. + + nodata : any number (optional, default is None) + Assign a nodata value to the Raster dataset when `src` is + a ndarray. If a nodata value is not specified then it is + determined based on the minimum permissible value for the + array's data type. + + file_path : str (optional, default None) + Path to save new Raster object if created from an array. + + driver : str (optional, default=None) + A GDAL compatible driver to use when initiating a raster + from a numpy array. + + tempdir : str, default is tempfile.tempdir + Path to a directory to store temporary files that are + produced during geoprocessing operations. + + in_memory : bool, default is False + Whether to initiate the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + Returns + ------- + pyspatialml.Raster + Raster object containing the src layers stacked into a + single object. + """ + self.files = list() + self.meta = None + self._block_shape = (256, 256) + self.tempdir = tempdir + self._internal = frozenset( + ["_internal", "files", "meta", "_block_shape", "tempdir"] + ) + + src_layers = [] + + # get temporary file name if file_path is None + if file_path is None and isinstance(src, np.ndarray): + file_path, tfile = self._tempfile(file_path) + driver = "GTiff" + + # initiate from numpy array + if isinstance(src, np.ndarray): + if src.ndim == 2: + src = src[np.newaxis] + count, height, width = src.shape + + if in_memory is True: + memfile = MemoryFile() + dst = memfile.open( + height=height, + width=width, + count=count, + driver=driver, + dtype=src.dtype, + crs=crs, + transform=transform, + nodata=nodata, + ) + dst.write(src) + else: + with rasterio.open( + file_path, + mode="w", + driver=driver, + height=height, + width=width, + count=count, + dtype=src.dtype, + crs=crs, + transform=transform, + nodata=nodata, + ) as dst: + dst.write(src) + dst = rasterio.open(file_path, "r") + + for i in range(dst.count): + band = rasterio.band(dst, i + 1) + rasterlayer = RasterLayer(band) + if in_memory is True: + rasterlayer.in_memory = True + src_layers.append(rasterlayer) + + if tfile is not None and in_memory is False: + for layer in src_layers: + layer._close = tfile.close + self._layers = src_layers + return + + # from a single file path + elif isinstance(src, str): + src_layers = [] + r = rasterio.open(src, mode="r", driver=driver) + for i in range(r.count): + band = rasterio.band(r, i + 1) + src_layers.append(RasterLayer(band)) + self._layers = src_layers + return + + # from a single RasterLayer + elif isinstance(src, RasterLayer): + self._layers = src + self._rename_inplace(list(self.names)[0], src.name) + return + + # from a single Raster + elif isinstance(src, Raster): + self._layers = [i for i in src.values()] + for old, new in zip(self.names, list(src.names)): + self._rename_inplace(old, new) + return + + # from a single rasterio.io.datasetreader/writer + elif isinstance(src, rasterio.io.DatasetReader): + src_layers = [] + for i in range(src.count): + band = rasterio.band(src, i + 1) + src_layers.append(RasterLayer(band)) + self._layers = src_layers + return + + # from a single rasterio.band object + elif isinstance(src, rasterio.Band): + self._layers = RasterLayer(src) + return + + # from a list of objects + elif isinstance(src, list): + # list of file paths (str) + if all(isinstance(x, str) for x in src): + src_layers = [] + for f in src: + r = rasterio.open(f, mode="r", driver=driver) + for i in range(r.count): + band = rasterio.band(r, i + 1) + src_layers.append(RasterLayer(band)) + + self._layers = src_layers + return + + # list of RasterLayer objects + elif all(isinstance(x, RasterLayer) for x in src): + self._layers = src + for old, new in zip(self.names, src): + self._rename_inplace(old, new.name) + return + + # list of rasterio.io.datasetreader objects + elif all(isinstance(x, rasterio.io.DatasetReader) for x in src): + src_layers = [] + for r in src: + for i in range(r.count): + band = rasterio.band(r, i + 1) + src_layers.append(RasterLayer(band)) + self._layers = src_layers + return + + # from a list of rasterio.band objects + elif all(isinstance(x, rasterio.Band) for x in src): + src_layers = [] + for band in src: + src_layers.append(RasterLayer(band)) + self._layers = src_layers + return + else: + raise ValueError("Cannot create a Raster object from a mixture of inputs") + + @property + def block_shape(self) -> Tuple[int, int]: + """Return the block shape in (height, width) used to read windows from the + Raster + """ + return self._block_shape + + @block_shape.setter + def block_shape(self, value) -> None: + if not isinstance(value, tuple): + raise ValueError( + "block_shape must be set using an integer tuple as (rows, " "cols)" + ) + rows, cols = value + + if not isinstance(rows, int) or not isinstance(cols, int): + raise ValueError( + "tuple must consist of integer values referring to number of " + "rows, cols" + ) + self._block_shape = (rows, cols) + + def set_block_shape(self, value) -> None: + """Set the block shape of the raster, i.e. the height and width + of windows to read in chunks for the predict, predict_proba, + apply, and other supported-methods. + + Note block shape can also be set with `myraster.block_shape = (500, 500)` + + Parameters + ---------- + value : tuple + A tuple of (height, width) for the block window + """ + self.block_shape = value + + @property + def count(self) -> int: + """Return the number of layers in the Raster""" + return len(self.loc) + + @property + def crs(self) -> rasterio.crs.CRS: + """Return to crs of the Raster""" + return self.meta["crs"] + + @crs.setter + def crs(self, value) -> None: + self.meta["crs"] = value + + @property + def transform(self) -> affine.Affine: + """Return the transform of the Raster""" + return self.meta["transform"] + + @transform.setter + def transform(self, value) -> None: + self.meta["transform"] = value + + @property + def width(self) -> int: + """Return the width (number of columns) in the Raster""" + return self.meta["width"] + + @property + def height(self) -> int: + """Return the height (number of rows) in the Raster""" + return self.meta["height"] + + @property + def shape(self) -> Tuple[int, int]: + """Return the shape (height, width) of the Raster""" + return self.height, self.width + + @property + def res(self) -> Tuple[float, float]: + """Return a tuple of the resolution of the Raster in (width, height)""" + return abs(self.meta["transform"].a), abs(self.meta["transform"].e) + + @property + def bounds(self) -> namedtuple: + """Return the bounding box of the raster in (left, bottom, right, top)""" + bounds = rasterio.transform.array_bounds( + self.height, self.width, self.transform + ) + BoundingBox = namedtuple("BoundingBox", ["left", "bottom", "right", "top"]) + return BoundingBox(bounds[0], bounds[1], bounds[2], bounds[3]) + + @property + def dtypes(self) -> list: + """Return the dtype of each layer in the Raster as a list""" + dtypes = list() + + for layer in self.loc.values(): + dtypes.append(layer.dtype) + + return dtypes + + @property + def nodatavals(self) -> list: + """Return the nodata value of each layer in the Raster as a list""" + nodatavals = list() + + for layer in self.loc.values(): + try: + nodatavals.append(layer.nodata) + except: + nodatavals.append(None) + + return nodatavals + + @property + def _layers(self) -> dict: + return self.loc + + @_layers.setter + def _layers(self, layers) -> None: + """Assign RasterLayer objects to the Raster + + The function assigns the layers to the loc indexer, updates + the `files` attribute and assigns syntactically-correct names + to each layer. + + Parameters + ---------- + layers : list + A list of pyspatialml.RasterLayer objects + """ + if isinstance(layers, RasterLayer): + layers = [layers] + + if all(isinstance(x, type(layers[0])) for x in layers) is False: + raise ValueError("Cannot create a Raster object from a mixture of inputs") + + meta = self._check_alignment(layers) + + if meta is False: + raise ValueError( + "Raster datasets do not have the same dimensions/transform" + ) + + # reset locindexer + self.files = list() + for key in self.loc.keys(): + self.loc.pop(key) + + # update global Raster object attributes with new values + names = [i.name for i in layers] + names = self._fix_names(names) + + # update attributes per dataset + for layer, name in zip(layers, names): + self.files.append(layer.file) + layer.name = name + self.loc[name] = layer + + self.meta = dict( + crs=meta["crs"], + transform=meta["transform"], + width=meta["width"], + height=meta["height"], + count=self.count, + dtype=np.result_type(*self.dtypes), + ) + + @staticmethod + def _fix_names(combined_names): + """Adjusts the names of pyspatialml.RasterLayer objects within the + Raster when appending new layers. + + This avoids the Raster object containing duplicated names in the + case that multiple RasterLayers are appended with the same name. + + In the case of duplicated names, the RasterLayer names are appended + with a `_n` with n = 1, 2, 3 .. n. + + Parameters + ---------- + combined_names : list + List of str representing names of RasterLayers. Any duplicates + will have a suffix appended to them. + + Returns + ------- + list + List with adjusted names + """ + counts = Counter(combined_names) + + for s, num in counts.items(): + if num > 1: + for suffix in range(1, num + 1): + if s + "_" + str(suffix) not in combined_names: + combined_names[combined_names.index(s)] = s + "_" + str(suffix) + else: + i = 1 + while s + "_" + str(i) in combined_names: + i += 1 + combined_names[combined_names.index(s)] = s + "_" + str(i) + + return combined_names + + @staticmethod + def _check_alignment(layers): + """Check that a list of raster datasets are aligned with the same + pixel dimensions and geotransforms. + + Parameters + ---------- + layers : list + List of pyspatialml.RasterLayer objects. + + Returns + ------- + dict or False + Dict of metadata if all layers are spatially aligned, otherwise + returns False. + """ + + src_meta = [] + for layer in layers: + src_meta.append(layer.ds.meta.copy()) + + if not all(i["crs"] == src_meta[0]["crs"] for i in src_meta): + Warning("crs of all rasters does not match, possible unintended consequences") + + if not all( + [ + i["height"] == src_meta[0]["height"] + or i["width"] == src_meta[0]["width"] + or i["transform"] == src_meta[0]["transform"] + for i in src_meta + ] + ): + return False + + else: + return src_meta[0] + + def _check_supported_dtype(self, dtype=None) -> str: + """Method to check that a dtype is compatible with GDAL or + generate a compatible dtype from an array + + Parameters + ---------- + dtype : str, dtype, ndarray or None + Pass a dtype (as a string or dtype) to check compatibility. + Pass an array to generate a compatible dtype from the + array. Pass None to use the existing dtype of the parent + Raster object. + + Returns + ------- + dtype : dtype + GDAL compatible dtype + """ + if dtype is None: + dtype = self.meta["dtype"] + + elif isinstance(dtype, np.ndarray): + dtype = rasterio.dtypes.get_minimum_dtype(dtype) + + else: + if rasterio.dtypes.check_dtype(dtype) is False: + raise AttributeError( + "{dtype} is not a support GDAL dtype".format(dtype=dtype) + ) + + return dtype + + def _tempfile(self, file_path) -> Tuple[str, str]: + """Returns a TemporaryFileWrapper and file path if a file_path + parameter is None + """ + if file_path is None: + if os.name != "nt": + tfile = tempfile.NamedTemporaryFile(dir=self.tempdir, suffix=".tif") + file_path = tfile.name + else: + tfile = TempRasterLayer() + file_path = tfile.name + + else: + tfile = None + + return file_path, tfile + + def _copy(self, src, names=None): + """Return a new Raster object from a list of files but + retaining the attributes of the parent Raster. + + Designed to be used internally to copy a Raster object. + + Parameters + ---------- + src : List of RasterLayers or file paths + List of RasterLayers or file paths used create the new + Raster object. + + names : list (optional, default None) + List to name the RasterLayer objects in the stack. If not + supplied then the names will be generated from the file + names. + + Returns + ------- + pyspatialml.Raster + """ + if not isinstance(src, (list, ValuesView)): + src = [src] + + raster = Raster(src) + + # rename and copy attributes + if names is not None: + for (old, new) in zip(raster.names, names): + raster._rename_inplace(old, new) + + for old_layer, new_layer in zip(self.loc.values(), list(raster.loc.values())): + new_layer.cmap = old_layer.cmap + new_layer.norm = old_layer.norm + new_layer.categorical = old_layer.categorical + + raster.block_shape = self.block_shape + + return raster + + @staticmethod + def _apply_transformer(img, transformer): + img = np.ma.masked_invalid(img) + mask = img.mask.copy() + + # reshape into 2D array + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + flat_pixels = img.reshape((rows * cols, n_features)) + flat_pixels = flat_pixels.filled(0) + + # predict and replace mask + result = transformer.transform(flat_pixels) + + # reshape the prediction from a 1D into 3D array [band, row, col] + result = result.reshape((n_features, rows, cols)) + result = np.ma.masked_array(data=result, mask=mask, copy=True) + + return result + + def head(self) -> np.ndarray: + """Return the first 10 rows from the Raster as a ndarray""" + window = Window(col_off=0, row_off=0, width=20, height=10) + return self.read(window=window) + + def tail(self) -> np.ndarray: + """Return the last 10 rows from the Raster as a ndarray""" + window = Window( + col_off=self.width - 20, row_off=self.height - 10, width=20, height=10 + ) + return self.read(window=window) + + def close(self) -> None: + """Close all of the RasterLayer objects in the Raster. + + Note that this will cause any rasters based on temporary files + to be removed. This is intended as a method of clearing + temporary files that may have accumulated during an analysis + session. + """ + for layer in self.loc.values(): + layer.close() + + def copy(self, subset=None): + """Creates a shallow copy of a Raster object + + Note that shallow in the context of a Raster object means that + an immutable copy of the object is made, however the on-disk and + in-memory file locations remain the same. + + Parameters + ---------- + subset : opt + A list of layer names to subset while copying. + + Returns + ------- + Raster + """ + if subset is not None: + if isinstance(subset, str): + subset = [subset] + layers = list(self.loc[subset].values()) + else: + layers = list(self.loc.values()) + + return self._copy(layers) + + def block_shapes(self, rows, cols): + """Generator for windows for optimal reading and writing based + on the raster format Windows and returns as a tuple with xoff, + yoff, width, height. + + Parameters + ---------- + rows : int + Height of window in rows. + + cols : int + Width of window in columns. + """ + for i, col in enumerate(range(0, self.width, cols)): + if col + cols < self.width: + num_cols = cols + else: + num_cols = self.width - col + + for j, row in enumerate(range(0, self.height, rows)): + if row + rows < self.height: + num_rows = rows + else: + num_rows = self.height - row + + yield Window(col, row, num_cols, num_rows) + + def read( + self, + masked=False, + window=None, + out_shape=None, + resampling="nearest", + as_df=False, + **kwargs + ) -> np.ndarray: + """Reads data from the Raster object into a numpy array. + + Parameters + ---------- + masked : bool (default False) + Read data into a masked array. + + window : rasterio.window.Window object (optional, default None) + Tuple of col_off, row_off, width, height of a window of + data to read a chunk of data into a ndarray. + + out_shape : tuple (optional, default None) + Shape of shape of array (rows, cols) to read data into + using decimated reads. + + resampling : str (default 'nearest') + Resampling method to use when applying decimated reads when + out_shape is specified. Supported methods are: 'average', + 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', + 'max', 'med', 'min', 'mode', 'q1', 'q3'. + + as_df : bool (default False) + Whether to return the data as a pandas.DataFrame with + columns named by the RasterLayer names. + + **kwargs : dict + Other arguments to pass to rasterio.DatasetReader.read method + + Returns + ------- + ndarray + Raster values in 3d ndarray with the dimensions in order + of (band, row, and column). + """ + dtype = self.meta["dtype"] + + # get window to read from window or height/width of dataset + if window is None: + width = self.width + height = self.height + else: + width = window.width + height = window.height + + # decimated reads using nearest neighbor resampling + if out_shape: + height, width = out_shape + + # read bands separately into numpy array + if masked is True: + arr = np.ma.zeros((self.count, height, width), dtype=dtype) + else: + arr = np.zeros((self.count, height, width), dtype=dtype) + + for i, layer in enumerate(self.loc.values()): + arr[i, :, :] = layer.read( + masked=masked, + window=window, + out_shape=out_shape, + resampling=resampling, + **kwargs + ) + + if masked is True: + arr[i, :, :] = np.ma.MaskedArray( + data=arr[i, :, :], mask=np.isfinite(arr[i, :, :]).mask + ) + + if as_df is True: + # reshape to rows, cols, bands + arr = arr.transpose(1, 2, 0) + arr_flat = arr.reshape((arr.shape[0] * arr.shape[1], arr.shape[2])) + df = pd.DataFrame(data=arr_flat, columns=self.names) + return df + + return arr + + def write( + self, file_path, driver="GTiff", dtype=None, nodata=None, **kwargs + ): + """Write the Raster object to a file. + + Overrides the write RasterBase class method, which is a partial + function of the rasterio.DatasetReader.write method. + + Parameters + ---------- + file_path : str + File path used to save the Raster object. + + driver : str (default is 'GTiff'). + Name of GDAL driver used to save Raster data. + + dtype : str (opt, default None) + Optionally specify a numpy compatible data type when + saving to file. If not specified, a data type is selected + based on the data types of RasterLayers in the Raster + object. + + nodata : any number (opt, default None) + Optionally assign a new nodata value when saving to file. + If not specified a nodata value based on the minimum + permissible value for the data types of RasterLayers in the + Raster object is used. Note that this does not change the + pixel nodata values of the raster, it only changes the + metadata of what value represents a nodata pixel. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + New Raster object from saved file. + """ + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + meta = self.meta.copy() + meta["driver"] = driver + meta["nodata"] = nodata + meta["dtype"] = dtype + meta.update(kwargs) + + with rasterio.open(file_path, mode="w", **meta) as dst: + + for i, layer in enumerate(self.loc.values()): + arr = layer.read() + arr[arr == layer.nodata] = nodata + dst.write(arr.astype(dtype), i + 1) + + return self._copy(file_path, self.names) + + def predict_proba( + self, + estimator, + file_path=None, + in_memory=False, + indexes=None, + driver="GTiff", + dtype=None, + nodata=None, + constants=None, + progress=False, + **kwargs + ): + """Apply class probability prediction of a scikit learn model to a Raster. + + Parameters + ---------- + estimator : estimator object implementing 'fit' + The object to use to fit the data. + + file_path : str (optional, default None) + Path to a GeoTiff raster for the prediction results. If not + specified then the output is written to a temporary file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + indexes : list of integers (optional, default None) + List of class indices to export. In some circumstances, + only a subset of the class probability estimations are + desired, for instance when performing a binary + classification only the probabilities for the positive + class may be desired. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Optionally specify a GDAL compatible data type when saving + to file. If not specified, a data type is set based on the + data type of the prediction. + + nodata : any number (optional, default None) + Nodata value for file export. If not specified then the + nodata value is derived from the minimum permissible value + for the given data type. + + progress : bool (default False) + Show progress bar for prediction. + + constants: list-like object or a dict (optional, default None) + Constant features to add to the Raster object with each value + in a list or 1d ndarray representing an additional feature. + + If a list-like object of values os passed, then each numeric + value will be appended as constant features to the last + columns in the data. It is therefore important that all + features including constant features are present in the same + order as what was used to train the model. + + If a dict is passed, then the keys of the dict must refer to + the names of raster layers in the Raster object. In this case, + the values of the dict will replace the values of the raster + layers in the Raster object. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster containing predicted class probabilities. Each + predicted class is represented by a RasterLayer object. + The RasterLayers are named `prob_n` for 1,2,3..n, with `n` + based on the index position of the classes, not the number + of the class itself. + + For example, a classification model predicting classes with + integer values of 1, 3, and 5 would result in three + RasterLayers named 'prob_1', 'prob_2' and 'prob_3'. + """ + # some checks + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + # n_jobs = get_num_workers(n_jobs) + probfun = partial( + predict_prob, + estimator=estimator, + constants=constants, + names=list(self.names), + ) + + # perform test prediction + window = Window(0, 0, 1, 1) + img = self.read(masked=True, window=window) + img = np.ma.masked_invalid(img) + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + n_samples = rows * cols + flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) + flat_pixels = flat_pixels.filled(0) + + if constants is not None: + flat_pixels = stack_constants(flat_pixels, constants, list(self.names)) + + result = estimator.predict_proba(flat_pixels) + + if isinstance(indexes, int): + indexes = range(indexes, indexes + 1) + + elif indexes is None: + indexes = np.arange(0, result.shape[1]) + + # check dtype and nodata + if dtype is None: + dtype = self._check_supported_dtype(result) + else: + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + # open output file with updated metadata + meta = self.meta.copy() + count = len(indexes) + meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) + meta.update(kwargs) + + # get windows + windows = [w for w in self.block_shapes(*self.block_shape)] + data_gen = ((w, self.read(window=w, masked=True)) for w in windows) + counter = tqdm(windows, disable=not progress, total=len(windows)) + + # apply prediction function + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + for w, res, pbar in zip(windows, map(probfun, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res[indexes, :, :].astype(dtype), window=w) + + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open( + height=meta["height"], + width=meta["width"], + count=meta["count"], + dtype=meta["dtype"], + crs=meta["crs"], + transform=meta["transform"], + nodata=meta["nodata"], + driver=driver, + ) + + for w, res, pbar in zip(windows, map(probfun, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res[indexes, :, :].astype(dtype), window=w) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + + for i in output_dst: + i.in_memory = True + + # create new Raster object with the result + prefix = "prob_" + names = [prefix + str(i) for i in range(len(indexes))] + new_raster = self._copy(output_dst, names) + + # override close method + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def predict( + self, + estimator, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + progress=False, + constants=None, + **kwargs + ): + """Apply prediction of a scikit learn model to a Raster. + + The model can represent any scikit learn model or compatible + api with a `fit` and `predict` method. These can consist of + classification or regression models. Multi-class + classifications and multi-target regressions are also + supported. + + Parameters + ---------- + estimator : estimator object implementing 'fit' + The object to use to fit the data. + + file_path : str (optional, default None) + Path to a GeoTiff raster for the prediction results. If + not specified then the output is written to a temporary + file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store + the data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export + + dtype : str (optional, default None) + Optionally specify a GDAL compatible data type when saving + to file. If not specified, np.float32 is assumed. + + nodata : any number (optional, default None) + Nodata value for file export. If not specified then the + nodata value is derived from the minimum permissible value + for the given data type. + + progress : bool (default False) + Show progress bar for prediction. + + constants: list-like object or a dict (optional, default None) + Constant features to add to the Raster object with each value + in a list or 1d ndarray representing an additional feature. + + If a list-like object of values os passed, then each numeric + value will be appended as constant features to the last + columns in the data. It is therefore important that all + features including constant features are present in the same + order as what was used to train the model. + + If a dict is passed, then the keys of the dict must refer to + the names of raster layers in the Raster object. In this case, + the values of the dict will replace the values of the raster + layers in the Raster object. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster object containing prediction results as a + RasterLayers. For classification and regression models, the + Raster will contain a single RasterLayer, unless the model + is multi-class or multi-target. Layers are named + automatically as `pred_raw_n` with n = 1, 2, 3 ..n. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + # n_jobs = get_num_workers(n_jobs) + + # determine output count for multi-class or multi-target cases + window = Window(0, 0, 1, 1) + img = self.read(masked=True, window=window) + img = np.ma.masked_invalid(img) + n_features, rows, cols = img.shape[0], img.shape[1], img.shape[2] + n_samples = rows * cols + flat_pixels = img.transpose(1, 2, 0).reshape((n_samples, n_features)) + flat_pixels = flat_pixels.filled(0) + + if constants is not None: + flat_pixels = stack_constants(flat_pixels, constants, list(self.names)) + + result = estimator.predict(flat_pixels) + + if result.ndim > 1: + n_outputs = result.shape[result.ndim - 1] + else: + n_outputs = 1 + + indexes = np.arange(0, n_outputs) + + # chose prediction function + if len(indexes) == 1: + if constants is not None: + predfun = partial( + predict_output, + estimator=estimator, + constants=constants, + names=list(self.names), + ) + else: + predfun = partial( + predict_output, + estimator=estimator, + constants=constants, + names=list(self.names), + ) + else: + predfun = partial( + predict_multioutput, + estimator=estimator, + constants=constants, + names=list(self.names), + ) + + # check dtype and nodata + if dtype is None: + dtype = self._check_supported_dtype(result) + else: + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + # open output file with updated metadata + meta = self.meta.copy() + count = len(indexes) + meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) + meta.update(kwargs) + + # get windows + windows = [w for w in self.block_shapes(*self.block_shape)] + data_gen = ((w, self.read(window=w, masked=True)) for w in windows) + counter = tqdm(windows, disable=not progress, total=len(windows)) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + for w, res, pbar in zip(windows, map(predfun, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res[indexes, :, :].astype(dtype), window=w) + + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open( + height=meta["height"], + width=meta["width"], + count=meta["count"], + dtype=meta["dtype"], + crs=meta["crs"], + driver=driver, + transform=meta["transform"], + nodata=meta["nodata"], + ) + + for w, res, pbar in zip(windows, map(predfun, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res[indexes, :, :].astype(dtype), window=w) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + + for i in output_dst: + i.in_memory = True + + # create new Raster object with the result + prefix = "pred_raw_" + names = [prefix + str(i) for i in range(len(indexes))] + new_raster = self._copy(output_dst, names) + + # override close method + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def append(self, other, in_place=False): + """Method to add new RasterLayers to a Raster object. + + Note that this modifies the Raster object in-place by default. + + Parameters + ---------- + other : Raster object, or list of Raster objects + Object to append to the Raster. + + in_place : bool (default False) + Whether to change the Raster object in-place or leave + original and return a new Raster object. + + Returns + ------- + Raster + Returned only if `in_place` is False + """ + if isinstance(other, Raster): + other = [other] + + combined_names = self.names + combined_layers = list(self.loc.values()) + + for new_raster in other: + if not isinstance(new_raster, Raster): + raise AttributeError(new_raster + " is not a pyspatialml.Raster object") + + # check that other raster does not result in duplicated names + combined_names = list(combined_names) + list(new_raster.names) + combined_names = self._fix_names(combined_names) + + # update layers and names + combined_layers = combined_layers + list(new_raster.loc.values()) + + for layer, name in zip(combined_layers, combined_names): + layer.names = [name] + + if in_place is True: + self._layers = combined_layers + self.names = combined_names + else: + new_raster = self._copy(self.files, self.names) + new_raster._layers = combined_layers + return new_raster + + def drop(self, labels, in_place=False): + """Drop individual RasterLayers from a Raster object + + Note that this modifies the Raster object in-place by default. + + Parameters + --------- + labels : single label or list-like + Index (int) or layer name to drop. Can be a single integer + or label, or a list of integers or labels. + + in_place : bool (default False) + Whether to change the Raster object in-place or leave + original and return a new Raster object. + + Returns + ------- + pyspatialml.Raster + Returned only if `in_place` is True + """ + # convert single label to list + if isinstance(labels, (str, int)): + labels = [labels] + + # numerical index based subsetting + if len([i for i in labels if isinstance(i, int)]) == len(labels): + subset_layers = [ + v for (i, v) in enumerate(list(self.loc.values())) if i not in labels + ] + + # str label based subsetting + elif len([i for i in labels if isinstance(i, str)]) == len(labels): + subset_layers = [ + v + for (i, v) in enumerate(list(self.loc.values())) + if list(self.names)[i] not in labels + ] + + else: + raise ValueError( + "Cannot drop layers based on mixture of indexes and labels" + ) + + if in_place is True: + self._layers = subset_layers + else: + new_raster = self._copy(self.files, self.names) + new_raster._layers = subset_layers + + return new_raster + + def rename(self, names, in_place=False): + """Rename a RasterLayer within the Raster object. + + Parameters + ---------- + names : dict + dict of old_name : new_name + + in_place : bool (default False) + Whether to change names of the Raster object in-place or + leave original and return a new Raster object. + + Returns + ------- + pyspatialml.Raster + Returned only if `in_place` is False + """ + if in_place is True: + for old_name, new_name in names.items(): + self._rename_inplace(old_name, new_name) + else: + new_raster = self._copy(src=[v for (_, v) in self.items()]) + + for old_name, new_name in names.items(): + new_raster._rename_inplace(old_name, new_name) + + return new_raster + + def mask( + self, + shapes, + invert=False, + crop=True, + pad=False, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + **kwargs + ): + """Mask a Raster object based on the outline of shapes in a + geopandas.GeoDataFrame + + Parameters + ---------- + shapes : geopandas.GeoDataFrame + GeoDataFrame containing masking features. + + invert : bool (default False) + If False then pixels outside shapes will be masked. If True + then pixels inside shape will be masked. + + crop : bool (default True) + Crop the raster to the extent of the shapes. + + pad : bool (default False) + If True, the features will be padded in each direction by + one half of a pixel prior to cropping raster. + + file_path : str (optional, default None) + File path to save to resulting Raster. If not supplied + then the resulting Raster is saved to a temporary file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store + the data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Coerce RasterLayers to the specified dtype. If not + specified then the cropped Raster is created using the + existing dtype, which usesa dtype that can accommodate the + data types of all of the individual RasterLayers. + + nodata : any number (optional, default None) + Nodata value for cropped dataset. If not specified then a + nodata value is set based on the minimum permissible value + of the Raster's data type. Note that this changes the + values of the pixels to the new nodata value, and changes + the metadata of the raster. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + pyspatialml.Raster + Raster with masked layers. + """ + # some checks + if invert is True: + crop = False + + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + meta = self.meta.copy() + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + meta["dtype"] = dtype + + masked_ndarrays = [] + + for layer in self.loc.values(): + # set pixels outside of mask to raster band's nodata value + masked_arr, transform = rasterio.mask.mask( + dataset=layer.ds, + shapes=[shapes.geometry.unary_union], + filled=False, + invert=invert, + crop=crop, + pad=pad, + ) + + if layer.ds.count > 1: + masked_arr = masked_arr[layer.bidx - 1, :, :] + + else: + masked_arr = np.ma.squeeze(masked_arr) + + masked_ndarrays.append(masked_arr) + + # stack list of 2d arrays into 3d array + masked_ndarrays = np.ma.stack(masked_ndarrays) + + # write to file + meta["transform"] = transform + meta["driver"] = driver + meta["nodata"] = nodata + meta["height"] = masked_ndarrays.shape[1] + meta["width"] = masked_ndarrays.shape[2] + meta.update(kwargs) + masked_ndarrays = masked_ndarrays.filled(fill_value=nodata) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(masked_ndarrays.astype(dtype)) + output_dst = file_path + else: + with MemoryFile() as memfile: + dst = memfile.open(**meta) + dst.write(masked_ndarrays.astype(dtype)) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + for i in output_dst: + i.in_memory = True + + # create new Raster object with the result + new_raster = self._copy(output_dst, self.names) + + # override close method + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def intersect( + self, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + **kwargs + ): + """Perform a intersect operation on the Raster object. + + Computes the geometric intersection of the RasterLayers with + the Raster object. This will cause nodata values in any of + the rasters to be propagated through all of the output rasters. + + Parameters + ---------- + file_path : str (optional, default None) + File path to save to resulting Raster. If not supplied then + the resulting Raster is saved to a temporary file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Coerce RasterLayers to the specified dtype. If not + specified then the new intersected Raster is created using + the dtype of the existing Raster dataset, which uses a + dtype that can accommodate the data types of all of the + individual RasterLayers. + + nodata : any number (optional, default None) + Nodata value for new dataset. If not specified then a + nodata value is set based on the minimum permissible value + of the Raster's data type. Note that this changes the + values of the pixels that represent nodata to the new + value. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster with layers that are masked based on a union of all + masks in the suite of RasterLayers. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + meta = self.meta.copy() + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + arr = self.read(masked=True) + mask_2d = arr.mask.any(axis=0) + + # repeat mask for n_bands + mask_3d = np.repeat(a=mask_2d[np.newaxis, :, :], repeats=self.count, axis=0) + + intersected_arr = np.ma.masked_array(arr, mask=mask_3d, fill_value=nodata) + intersected_arr = np.ma.filled(intersected_arr, fill_value=nodata) + + meta["driver"] = driver + meta["nodata"] = nodata + meta["dtype"] = dtype + meta.update(kwargs) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(intersected_arr.astype(dtype)) + output_dst = file_path + else: + with MemoryFile() as memfile: + dst = memfile.open(**meta) + dst.write(intersected_arr.astype(dtype)) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + for i in output_dst: + i.in_memory = True + + # create new Raster object with the result + new_raster = self._copy(output_dst, self.names) + + # override close method + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def crop( + self, + bounds, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + **kwargs + ): + """Crops a Raster object by the supplied bounds. + + Parameters + ---------- + bounds : tuple + A tuple containing the bounding box to clip by in the form + of (xmin, ymin, xmax, ymax). + + file_path : str (optional, default None) + File path to save to cropped raster. If not supplied then + the cropped raster is saved to a temporary file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store + the data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff'). Default is 'GTiff' + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Coerce RasterLayers to the specified dtype. If not + specified then the new intersected Raster is created using + the dtype of theexisting Raster dataset, which uses a + dtype that can accommodate the data types of all of the + individual RasterLayers. + + nodata : any number (optional, default None) + Nodata value for new dataset. If not specified then a + nodata value is set based on the minimum permissible value + of the Raster's data type. Note that this does not change + the pixel nodata values of the raster, it only changes + the metadata of what value represents a nodata pixel. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster cropped to new extent. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + dtype = self._check_supported_dtype(dtype) + if nodata is None: + nodata = get_nodata_value(dtype) + + # get row, col positions for bounds + xmin, ymin, xmax, ymax = bounds + rows, cols = rasterio.transform.rowcol( + transform=self.transform, xs=(xmin, xmax), ys=(ymin, ymax) + ) + + # create window covering the min/max rows and cols + window = Window( + col_off=min(cols), + row_off=min(rows), + width=max(cols) - min(cols), + height=max(rows) - min(rows), + ) + cropped_arr = self.read(masked=True, window=window) + + # calculate the new transform + new_transform = rasterio.transform.from_bounds( + west=xmin, + south=ymin, + east=xmax, + north=ymax, + width=cropped_arr.shape[2], + height=cropped_arr.shape[1], + ) + + # update the destination meta + meta = self.meta.copy() + meta.update( + transform=new_transform, + width=cropped_arr.shape[2], + height=cropped_arr.shape[1], + driver=driver, + nodata=nodata, + dtype=dtype, + ) + meta.update(kwargs) + cropped_arr = cropped_arr.filled(fill_value=nodata) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(cropped_arr.astype(dtype)) + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open(**meta) + dst.write(cropped_arr.astype(dtype)) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + for i in output_dst: + i.in_memory = True + + new_raster = self._copy(output_dst, self.names) + + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def to_crs( + self, + crs, + resampling="nearest", + file_path=None, + in_memory=False, + driver="GTiff", + nodata=None, + n_jobs=1, + warp_mem_lim=0, + progress=False, + **kwargs + ): + """Reprojects a Raster object to a different crs. + + Parameters + ---------- + crs : rasterio.transform.CRS object, or dict + Example: CRS({'init': 'EPSG:4326'}) + + resampling : str (default 'nearest') + Resampling method to use. One of the following: + nearest, + bilinear, + cubic, + cubic_spline, + lanczos, + average, + mode, + max (GDAL >= 2.2), + min (GDAL >= 2.2), + med (GDAL >= 2.2), + q1 (GDAL >= 2.2), + q3 (GDAL >= 2.2) + + file_path : str (optional, default None) + Optional path to save reprojected Raster object. If not + specified then a tempfile is used. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + nodata : any number (optional, default None) + Nodata value for new dataset. If not specified then the + existing nodata value of the Raster object is used, which + can accommodate the dtypes of the individual layers in the + Raster. + + n_jobs : int (default 1) + The number of warp worker threads. + + warp_mem_lim : int (default 0) + The warp operation memory limit in MB. Larger values allow + the warp operation to be carried out in fewer chunks. The + amount of memory required to warp a 3-band uint8 2000 row + x 2000 col raster to a destination of the same size is + approximately 56 MB. The default (0) means 64 MB with GDAL + 2.2. + + progress : bool (default False) + Optionally show progress of transform operations. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster following reprojection. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + if nodata is None: + nodata = get_nodata_value(self.meta["dtype"]) + + resampling_methods = [i.name for i in rasterio.enums.Resampling] + if resampling not in resampling_methods: + raise ValueError( + "Resampling method must be one of {}:".format(resampling_methods) + ) + + dst_transform, dst_width, dst_height = calculate_default_transform( + src_crs=self.crs, + dst_crs=crs, + width=self.width, + height=self.height, + left=self.bounds.left, + right=self.bounds.right, + bottom=self.bounds.bottom, + top=self.bounds.top, + ) + + meta = self.meta.copy() + meta["nodata"] = nodata + meta["width"] = dst_width + meta["height"] = dst_height + meta["transform"] = dst_transform + meta["crs"] = crs + meta.update(kwargs) + + if progress is True: + t = tqdm(total=self.count) + + if in_memory is False: + with rasterio.open(file_path, "w", driver=driver, **meta) as dst: + for i, layer in enumerate(self.loc.values()): + reproject( + source=rasterio.band(layer.ds, layer.bidx), + destination=rasterio.band(dst, i + 1), + resampling=rasterio.enums.Resampling[resampling], + num_threads=n_jobs, + warp_mem_lim=warp_mem_lim, + ) + + if progress is True: + t.update() + + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open(driver=driver, **meta) + for i, layer in enumerate(self.loc.values()): + reproject( + source=rasterio.band(layer.ds, layer.bidx), + destination=rasterio.band(dst, i + 1), + resampling=rasterio.enums.Resampling[resampling], + num_threads=n_jobs, + warp_mem_lim=warp_mem_lim, + ) + + if progress is True: + t.update() + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + + for i in output_dst: + i.in_memory = True + + new_raster = self._copy(output_dst, self.names) + + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def aggregate( + self, + out_shape, + resampling="nearest", + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + **kwargs + ): + """Aggregates a raster to (usually) a coarser grid cell size. + + Parameters + ---------- + out_shape : tuple + New shape in (rows, cols). + + resampling : str (default 'nearest') + Resampling method to use when applying decimated reads when + out_shape is specified. Supported methods are: 'average', + 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', + 'max', 'med', 'min', 'mode', 'q1', 'q3'. + + file_path : str (optional, default None) + File path to save to cropped raster. If not supplied then + the aggregated raster is saved to a temporary file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store + the data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Coerce RasterLayers to the specified dtype. If not + specified then the new intersected Raster is created using + the dtype of the existing Raster dataset, which uses a + dtype that can accommodate the data types of all of the + individual RasterLayers. + + nodata : any number (optional, default None) + Nodata value for new dataset. If not specified then a + nodata value is set based on the minimum permissible value + of the Raster's dtype. Note that this does not change the + pixel nodata values of the raster, it only changes the + metadata of what value represents a nodata pixel. + + kwargs : opt + Optional named arguments to pass to the format drivers. For + example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster object aggregated to a new pixel size. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + rows, cols = out_shape + arr = self.read(masked=True, out_shape=out_shape, resampling=resampling) + meta = self.meta.copy() + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + arr = arr.filled(fill_value=nodata) + + meta["driver"] = driver + meta["nodata"] = nodata + meta["height"] = rows + meta["width"] = cols + meta["dtype"] = dtype + bnd = self.bounds + meta["transform"] = rasterio.transform.from_bounds( + west=bnd.left, + south=bnd.bottom, + east=bnd.right, + north=bnd.top, + width=cols, + height=rows, + ) + meta.update(kwargs) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + dst.write(arr.astype(dtype)) + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open(**meta) + dst.write(arr.astype(dtype)) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + for i in output_dst: + i.in_memory = True + + new_raster = self._copy(output_dst, self.names) + + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def apply( + self, + function, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + progress=False, + function_args={}, + **kwargs + ): + """Apply user-supplied function to a Raster object. + + Parameters + ---------- + function : function + Function that takes an numpy array as a single argument. + + file_path : str (optional, default None) + Optional path to save calculated Raster object. If not + specified then a tempfile is used. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Coerce RasterLayers to the specified dtype. If not + specified then the new Raster is created using the dtype of + the calculation result. + + nodata : any number (optional, default None) + Nodata value for new dataset. If not specified then a + nodata value is set based on the minimum permissible value + of the Raster's data type. Note that this changes the + values of the pixels that represent nodata pixels. + + progress : bool (default False) + Optionally show progress of transform operations. + + function_args : dict (optional) + Optionally pass arguments to the `function` as a dict or + keyword arguments. + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + Raster + Raster containing the calculated result. + """ + tfile = None + + if in_memory is False: + file_path, tfile = self._tempfile(file_path) + + function = partial(function, **function_args) + + # perform test calculation determine dimensions, dtype, nodata + window = next(self.block_shapes(*self.block_shape)) + img = self.read(masked=True, window=window) + arr = function(img, **function_args) + + if arr.ndim > 2: + indexes = np.arange(1, arr.shape[0] + 1) + count = len(indexes) + else: + indexes = 1 + count = 1 + + dtype = self._check_supported_dtype(dtype) + + if nodata is None: + nodata = get_nodata_value(dtype) + + # open output file with updated metadata + meta = self.meta.copy() + meta.update(driver=driver, count=count, dtype=dtype, nodata=nodata) + meta.update(kwargs) + + # get windows + windows = [w for w in self.block_shapes(*self.block_shape)] + data_gen = (self.read(window=w, masked=True) for w in windows) + counter = tqdm(windows, total=len(windows), disable=not progress) + + if in_memory is False: + with rasterio.open(file_path, "w", **meta) as dst: + for w, res, pbar in zip(windows, map(function, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res.astype(dtype), window=w, indexes=indexes) + + output_dst = file_path + + else: + with MemoryFile() as memfile: + dst = memfile.open(**meta) + for w, res, pbar in zip(windows, map(function, data_gen), counter): + res = np.ma.filled(res, fill_value=nodata) + dst.write(res.astype(dtype), window=w, indexes=indexes) + + output_dst = [ + RasterLayer(rasterio.band(dst, i + 1)) for i in range(dst.count) + ] + + for i in output_dst: + i.in_memory = True + + # create new raster object with result + new_raster = self._copy(output_dst) + + # override close method + if tfile is not None: + for layer in new_raster.iloc: + layer._close = tfile.close + + return new_raster + + def to_pandas(self, max_pixels=None, resampling="nearest") -> pd.DataFrame: + """Raster to pandas DataFrame. + + Parameters + ---------- + max_pixels: int (default None) + Maximum number of pixels to sample. By default all pixels + are used. + + resampling : str (default 'nearest') + Resampling method to use when applying decimated reads when + out_shape is specified. Supported methods are: 'average', + 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', + 'max', 'med', 'min', 'mode', 'q1', 'q3'. + + Returns + ------- + pandas.DataFrame + DataFrame containing values of names of RasterLayers in + the Raster as columns, and pixel values as rows. + """ + + # read dataset using decimated reads + if max_pixels is not None: + rel_width = self.shape[1] / max_pixels + + if rel_width > 1: + col_scaling = round(max_pixels / rel_width) + row_scaling = max_pixels - col_scaling + else: + col_scaling = round(max_pixels * rel_width) + row_scaling = max_pixels - col_scaling + else: + row_scaling, col_scaling = self.shape[0], self.shape[1] + + out_shape = (row_scaling, col_scaling) + arr = self.read(masked=True, out_shape=out_shape, resampling=resampling) + bands, rows, cols = arr.shape + nodatavals = self.nodatavals + + # x and y grid coordinate arrays + x_range = np.linspace(start=self.bounds.left, stop=self.bounds.right, num=cols) + y_range = np.linspace(start=self.bounds.top, stop=self.bounds.bottom, num=rows) + xs, ys = np.meshgrid(x_range, y_range) + + arr = arr.reshape((bands, rows * cols)) + arr = arr.transpose() + df = pd.DataFrame( + data=np.column_stack((xs.flatten(), ys.flatten(), arr)), + columns=["x", "y"] + list(self.names), + ) + + # set nodata values to nan + for i, col_name in enumerate(self.names): + df.loc[df[col_name] == nodatavals[i], col_name] = np.nan + + return df + + def sample(self, size, strata=None, return_array=False, random_state=None): + """Generates a random sample of according to size, and samples + the pixel values. + + Parameters + ---------- + size : int + Number of random samples or number of samples per strata if + a `strata` object is supplied. + + strata : pyspatialml Raster object (opt) + Whether to use stratified instead of random sampling. Strata + can be supplied using another pyspatialml.Raster object. + + return_array : bool (opt), default=False + Optionally return extracted data as separate X and xy + masked numpy arrays. + + random_state : int (opt) + integer to use within random.seed. + + Returns + ------- + pandas.DataFrame + DataFrame containing values of names of RasterLayers in the Raster + if `return_array` is False. + + tuple + A tuple containing two elements if `return_array` is True: + + - numpy.ndarray + Numpy array of extracted raster values, typically 2d. + - numpy.ndarray + 2D numpy array of xy coordinates of extracted values. + """ + # set the seed + np.random.seed(seed=random_state) + + if not strata: + # create np array to store randomly sampled data + valid_samples = np.zeros((0, self.count)) + valid_coordinates = np.zeros((0, 2)) + + # loop until target number of samples is satisfied + satisfied = False + + n = size + while satisfied is False: + + # generate random row and column indices + Xsample = np.random.choice(range(0, self.width), n) + Ysample = np.random.choice(range(0, self.height), n) + + # create 2d numpy array with sample locations set to 1 + sample_raster = np.empty((self.height, self.width)) + sample_raster[:] = np.nan + sample_raster[Ysample, Xsample] = 1 + + # get indices of sample locations + rows, cols = np.nonzero(np.isnan(sample_raster) == False) + + # convert row, col indices to coordinates + xy = np.transpose(rasterio.transform.xy(self.transform, rows, cols)) + + # sample at random point locations + samples = self.extract_xy_chunked(xs=xy[:, 0], ys=xy[:, 1]) + + # append only non-masked data to each row of X_random + samples = samples.astype("float32").filled(np.nan) + invalid_ind = np.isnan(samples).any(axis=1) + samples = samples[~invalid_ind, :] + valid_samples = np.append(valid_samples, samples, axis=0) + + xy = xy[~invalid_ind, :] + valid_coordinates = np.append(valid_coordinates, xy, axis=0) + + # check to see if target_nsamples has been reached + if len(valid_samples) >= size: + satisfied = True + else: + n = size - len(valid_samples) + + else: + if strata.count != 1: + raise AttributeError( + "Strata must be a Raster object with a single band." + ) + + # get number of unique categories + strata_arr = strata.iloc[0].read(masked=True) + categories = np.unique(strata_arr.flatten()) + categories = categories[~categories.mask] + + # store selected coordinates + selected = np.zeros((0, 2)) + + for cat in categories: + + # get row,col positions for cat strata + ind = np.transpose(np.nonzero(strata_arr == cat)) + + if size > ind.shape[0]: + msg = ( + "Sample size is greater than number of pixels in " "strata {}" + ).format(str(ind)) + + msg = os.linesep.join([msg, "Sampling using replacement"]) + Warning(msg) + + # random sample + sample = np.random.uniform(0, ind.shape[0], size).astype("int") + xy = ind[sample, :] + + selected = np.append(selected, xy, axis=0) + + # convert row, col indices to coordinates + x, y = rasterio.transform.xy( + transform=self.transform, rows=selected[:, 0], cols=selected[:, 1] + ) + valid_coordinates = np.column_stack((x, y)) + + # extract data + valid_samples = self.extract_xy_chunked( + xs=valid_coordinates[:, 0], ys=valid_coordinates[:, 1] + ) + + # return as geopandas array as default (or numpy arrays) + if return_array is False: + gdf = pd.DataFrame(valid_samples, columns=self.names) + gdf["geometry"] = list( + zip(valid_coordinates[:, 0], valid_coordinates[:, 1]) + ) + gdf["geometry"] = gdf["geometry"].apply(Point) + gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) + return gdf + else: + return valid_samples, valid_coordinates + + def extract_xy(self, xys, return_array=False, progress=False): + """Samples pixel values using an array of xy locations. + + Parameters + ---------- + xys : 2d array-like + x and y coordinates from which to sample the raster + (n_samples, xys). + + return_array : bool (opt), default=False + By default the extracted pixel values are returned as a + geopandas.GeoDataFrame. If `return_array=True` then the + extracted pixel values are returned as a tuple of + numpy.ndarrays. + + progress : bool (opt), default=False + Show a progress bar for extraction. + + Returns + ------- + geopandas.GeoDataframe + Containing extracted data as point geometries if + `return_array=False`. + + numpy.ndarray + 2d masked array containing sampled raster values (sample, + bands) at the x,y locations. + """ + # extract pixel values + dtype = np.find_common_type([np.float32], self.dtypes) + X = np.ma.zeros((xys.shape[0], self.count), dtype=dtype) + t = tqdm(self.loc.values(), total=self.count, disable=not progress) + + for i, (layer, pbar) in enumerate(zip(self.loc.values(), t)): + sampler = sample_gen( + dataset=layer.ds, xy=xys, indexes=layer.bidx, masked=True + ) + v = np.ma.asarray([i for i in sampler]) + X[:, i] = v.flatten() + + # return as geopandas array as default (or numpy arrays) + if return_array is False: + gdf = pd.DataFrame(X, columns=self.names) + gdf["geometry"] = list(zip(xys[:, 0], xys[:, 1])) + gdf["geometry"] = gdf["geometry"].apply(Point) + gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) + return gdf + + return X + + def extract_xy_chunked(self, xs, ys, progress=False): + rows, cols = rowcol(self.transform, xs, ys) + rowcol_idx = np.column_stack((rows, cols)) + pixel_index = np.arange(rowcol_idx.shape[0]) + + # get row, col positions that are outside of the raster + negative_idx = (rowcol_idx < 0).any(axis=1) + outside_idx = (rowcol_idx[:, 0] >= self.shape[0]) | ( + rowcol_idx[:, 1] >= self.shape[1] + ) + + outsiders = np.logical_or(negative_idx, outside_idx) + valid = np.nonzero(outsiders == False)[0] + invalid = np.nonzero(outsiders == True)[0] + + # remove row, col > shape + rowcol_idx = rowcol_idx[~outsiders, :] + pixel_index = pixel_index[~outsiders] + + # lookup pixel values at row, col positons by chunk + windows = [w for w in self.block_shapes(*self.block_shape)] + data_gen = (self.read(window=w, masked=True) for w in windows) + t = tqdm(windows, total=len(windows), disable=not progress) + + dtype = np.result_type(np.float32, *self.dtypes) + X = np.ma.zeros((self.count, 0), dtype=dtype) + pixel_indices = np.zeros(0, dtype="int") + + for w, data, pbar in zip(windows, data_gen, t): + res, chunk_pixels = self.extract_by_chunk(data, w, rowcol_idx, pixel_index) + X = np.ma.concatenate((X, res), axis=1) + pixel_indices = np.concatenate((pixel_indices, chunk_pixels)) + + X = X.transpose((1, 0)) + + # insert empty rows to make input dimensions match output + output_arr = np.ma.zeros((len(rows), self.count)) + output_arr[pixel_indices, :] = X + output_arr[invalid, :].mask = True + output_arr[invalid, :] = None + + return output_arr + + def extract_vector(self, gdf, progress=False): + """Sample a Raster/RasterLayer using a geopandas GeoDataframe + containing points, lines or polygon features. + + Parameters + ---------- + gdf: geopandas.GeoDataFrame + Containing either point, line or polygon geometries. + Overlapping geometries will cause the same pixels to be + sampled. + + progress : bool (opt), default=False + Show a progress bar for extraction. + + Returns + ------- + geopandas.GeoDataframe + Containing extracted data as point geometries (one point + per pixel). The resulting GeoDataFrame is indexed using + a named pandas.MultiIndex, with `pixel_idx` index + referring to the index of each pixel that was sampled, and + the `geometry_idx` index referring to the index of the each + geometry in the supplied `gdf`. This makes it possible to + keep track of how sampled pixel relates to the original + geometries, i.e. multiple pixels being extracted within + the area of a single polygon that can be referred to using + the `geometry_idx`. + + The extracted data can subsequently be joined with the + attribute table of the supplied `gdf` using: + + training_py = geopandas.read_file(nc.polygons) + df = self.stack.extract_vector(gdf=training_py) + df = df.dropna() + + df = df.merge( + right=training_py.loc[:, ("id", "label")], + left_on="polygon_idx", + right_on="id", + right_index=True + ) + """ + # rasterize polygon and line geometries + if all(gdf.geom_type == "Polygon") or all(gdf.geom_type == "LineString"): + + shapes = [(geom, val) for geom, val in zip(gdf.geometry, gdf.index)] + arr = np.ma.zeros((self.height, self.width)) + arr[:] = -99999 + + arr = features.rasterize( + shapes=shapes, + fill=-99999, + out=arr, + transform=self.transform, + all_touched=True, + ) + + ids = arr[np.nonzero(arr != -99999)] + ids = ids.astype("int") + rows, cols = np.nonzero(arr != -99999) + xys = rasterio.transform.xy(transform=self.transform, rows=rows, cols=cols) + xys = np.transpose(xys) + + elif all(gdf.geom_type == "Point"): + ids = gdf.index.values + xys = gdf.bounds.iloc[:, 2:].values + + # extract raster pixels + X = self.extract_xy_chunked(xs=xys[:, 0], ys=xys[:, 1], progress=progress) + + # return as geopandas array as default (or numpy arrays) + X = pd.DataFrame( + data=X, columns=list(self.names), index=[pd.RangeIndex(0, X.shape[0]), ids] + ) + X.index.set_names(["pixel_idx", "geometry_idx"], inplace=True) + X["geometry"] = list(zip(xys[:, 0], xys[:, 1])) + X["geometry"] = X["geometry"].apply(Point) + X = gpd.GeoDataFrame(X, geometry="geometry", crs=self.crs) + + return X + + def extract_raster(self, src, progress=False): + """Sample a Raster object by an aligned raster of labelled pixels. + + Parameters + ---------- + src: rasterio DatasetReader + Single band raster containing labelled pixels as an open + rasterio DatasetReader object. + + progress : bool (opt), default=False + Show a progress bar for extraction. + + Returns + ------- + geopandas.GeoDataFrame + Geodataframe containing extracted data as point features if + `return_array=False` + """ + # open response raster and get labelled pixel indices and values + arr = src.read(1, masked=True) + rows, cols = np.nonzero(~arr.mask) + xys = np.transpose(rasterio.transform.xy(src.transform, rows, cols)) + ys = arr.data[rows, cols] + + # extract Raster object values at row, col indices + X = self.extract_xy_chunked(xs=xys[:, 0], ys=xys[:, 1], progress=progress) + + # summarize data + column_names = ["value"] + list(self.names) + gdf = pd.DataFrame(data=np.ma.column_stack((ys, X)), columns=column_names) + gdf["geometry"] = list(zip(xys[:, 0], xys[:, 1])) + gdf["geometry"] = gdf["geometry"].apply(Point) + gdf = gpd.GeoDataFrame(gdf, geometry="geometry", crs=self.crs) + + return gdf + + @staticmethod + def extract_by_chunk(arr, w, idx, pixel_idx): + d = idx.copy() + pixel_idx = pixel_idx.copy() + + # subtract chunk offset from row, col positions + d[:, 0] = d[:, 0] - w.row_off + d[:, 1] = d[:, 1] - w.col_off + + # remove negative row, col positions + pos = (d >= 0).all(axis=1) + d = d[pos, :] + pixel_idx = pixel_idx[pos] + + # remove row, col > shape + within_range = (d[:, 0] < arr.shape[1]) & (d[:, 1] < arr.shape[2]) + d = d[within_range, :] + pixel_idx = pixel_idx[within_range] + + extracted_data = arr[:, d[:, 0], d[:, 1]] + return (extracted_data, pixel_idx) + + def scale( + self, + centre=True, + scale=True, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + progress=False, + ): + """Standardize (centre and scale) a Raster object by + subtracting the mean and dividing by the standard deviation for + each layer in the object. + + The mean and standard deviation statistics are calculated + for each layer separately. + + Parameters + ---------- + centre : bool, default is True + Whether to subtract the mean from each layer. + + scale : bool, default is True + Whether to divide each layer by the standard deviation of + the layer. + + file_path : str (optional, default None) + Path to a GeoTiff raster for the prediction results. If + not specified then the output is written to a temporary + file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Optionally specify a GDAL compatible data type when saving + to file. If not specified, a data type is set based on the + data type of the prediction. + + nodata : any number (optional, default None) + Nodata value for file export. If not specified then the + nodata value is derived from the minimum permissible value + for the given data type. + + progress : bool (default False) + Show progress bar for operation. + + Returns + ------- + Pyspatialml.Raster object with rescaled data. + """ + + def scaler(x, means, sds): + for i, m, z in zip(range(x.shape[0]), means, sds): + x[i, :, :] = (x[i, :, :] - m) / z + return x + + if centre is True: + means = self.mean() + else: + means = np.repeat(0, self.count) + + if scale is True: + sds = self.stddev() + else: + sds = np.repeat(1, self.count) + + res = self.apply( + scaler, + file_path=file_path, + in_memory=in_memory, + driver=driver, + dtype=dtype, + nodata=nodata, + progress=progress, + function_args=dict(means=means, sds=sds), + ) + + return res + + def alter( + self, + transformer, + file_path=None, + in_memory=False, + driver="GTiff", + dtype=None, + nodata=None, + progress=False, + ): + """Apply a fitted scikit-learn transformer to a Raster object. + + Can be used to transform a raster using methods such as StandardScaler, + RobustScaler etc. + + Parameters + ---------- + transformer : a sklearn.preprocessing.Transformer object + + file_path : str (optional, default None) + Path to a GeoTiff raster for the prediction results. If + not specified then the output is written to a temporary + file. + + in_memory : bool, default is False + Whether to initiated the Raster from an array and store the + data in-memory using Rasterio's in-memory files. + + driver : str (default 'GTiff') + Named of GDAL-supported driver for file export. + + dtype : str (optional, default None) + Optionally specify a GDAL compatible data type when saving + to file. If not specified, a data type is set based on the + data type of the prediction. + + nodata : any number (optional, default None) + Nodata value for file export. If not specified then the + nodata value is derived from the minimum permissible value + for the given data type. + + progress : bool (default False) + Show progress bar for operation. + + Returns + ------- + Pyspatialml.Raster object with transformed data. + """ + res = self.apply( + self._apply_transformer, + file_path=file_path, + in_memory=in_memory, + driver=driver, + dtype=dtype, + nodata=nodata, + progress=progress, + function_args={"transformer": transformer}, + ) + + return res + + +class TempRasterLayer: + """Create a NamedTemporaryFile like object on Windows that has a + close method + + Workaround used on Windows which cannot open the file a second time + """ + + def __init__(self, tempdir=tempfile.tempdir): + self.tfile = tempfile.NamedTemporaryFile(dir=tempdir, suffix=".tif").name + self.name = self.tfile + + def close(self): + os.unlink(self.tfile) diff --git a/pyspatialml/rasterlayer.py b/pyspatialml/rasterlayer.py index 1823b87..1c9920c 100644 --- a/pyspatialml/rasterlayer.py +++ b/pyspatialml/rasterlayer.py @@ -1,440 +1,440 @@ -from functools import partial - -import os -import re -import numpy as np -import rasterio -from rasterio.io import MemoryFile - -from ._plotting import RasterLayerPlotMixin -from ._rasterstats import RasterLayerStatsMixin -from ._utils import get_nodata_value - - -class RasterLayer(RasterLayerStatsMixin, RasterLayerPlotMixin): - """Represents a single raster band derived from a single or - multi-band raster dataset - - Simple wrapper around a rasterio.Band object with additional - methods. Used because the Rasterio.Band.ds.read method reads - all bands from a multi-band dataset, whereas the RasterLayer read - method only reads a single band. - - Methods encapsulated in RasterLayer objects represent those that - typically would only be applied to a single-band of a raster, i.e. - sieve-clump, distance to non-NaN pixels, or arithmetic operations - on individual layers. - - Attributes - ---------- - bidx : int - The band index of the RasterLayer within the file dataset. - - dtype : str - The data type of the RasterLayer. - - ds : rasterio.band - The underlying rasterio.band object. - - name : str - A syntactically valid name for the RasterLayer. - - file : str - The file path to the dataset. - - nodata : any number - The number that is used to represent nodata pixels in the - RasterLayer. - - driver : str - The name of the GDAL format driver. - - meta : dict - A python dict storing the RasterLayer metadata. - - transform : affine.Affine object - The affine transform parameters. - - count : int - Number of layers; always equal to 1. - - shape: tuple - Shape of RasterLayer in (rows, columns) - - width, height: int - The width (cols) and height (rows) of the dataset. - - bounds : BoundingBox named tuple - A named tuple with left, bottom, right and top coordinates of - the dataset. - - cmap : str - The name of matplotlib map, or a custom - matplotlib.cm.LinearSegmentedColormap or ListedColormap object. - - norm : matplotlib.colors.Normalize (opt) - A matplotlib.colors.Normalize to apply to the RasterLayer. - This overides the norm attribute of the RasterLayer. - """ - - def __init__(self, band): - """Initiate a RasterLayer object - - Parameters - ---------- - band : a rasterio.Band object - """ - self.bidx = band.bidx - self.dtype = band.dtype - self.ds = band.ds - - if len(band.ds.files) > 0: - description = band.ds.descriptions[band.bidx-1] - if description is not None: - layer_name = self._make_name(band.ds.descriptions[band.bidx-1]) - else: - layer_name = self._make_name(band.ds.files[0]) - - self.name = layer_name - self.file = band.ds.files[0] - - else: - self.name = "in_memory" - self.file = None - - self.nodata = band.ds.nodata - self.driver = band.ds.meta["driver"] - self.meta = band.ds.meta - self.transform = band.ds.transform - self.crs = band.ds.crs - self.count = 1 - self.shape = band.shape - self.width = band.ds.width - self.height = band.ds.height - self.bounds = band.ds.bounds - self.in_memory = False - - self.cmap = "viridis" - self.norm = None - self.categorical = False - - @staticmethod - def _make_name(name): - """Converts a file basename to a valid class attribute name. - - Parameters - ---------- - name : str - File basename for converting to a valid class attribute name. - - Returns - ------- - valid_name : str - Syntactically correct name of layer so that it can form a class - instance attribute. - """ - basename = os.path.basename(name) - sans_ext = os.path.splitext(basename)[0] - - valid_name = sans_ext.replace(" ", "_").replace("-", "_").replace(".", "_") - - if valid_name[0].isdigit(): - valid_name = "x" + valid_name - - valid_name = re.sub(r"[\[\]\(\)\{\}\;]", "", valid_name) - valid_name = re.sub(r"_+", "_", valid_name) - - return valid_name - - def close(self): - self.ds.close() - - def _arith(self, function, other=None): - """General method for performing arithmetic operations on - RasterLayer objects - - Parameters - ---------- - function : function - Custom function that takes either one or two arrays, and - returns a single array following a pre-defined calculation. - - other : pyspatialml.RasterLayer (optional, default None) - If not specified, then a `function` should be provided that - performs a calculation using only the selected RasterLayer. - If `other` is specified, then a `function` should be - supplied that takes two ndarrays as arguments and performs a - calculation using both layers, i.e. layer1 - layer2. - - Returns - ------- - pyspatialml.RasterLayer - Returns a single RasterLayer containing the calculated - result. - """ - - driver = self.driver - - # if other is a RasterLayer then use the read method to get the - # array, otherwise assume other is a scalar or array - if isinstance(other, RasterLayer): - result = function(self.read(masked=True), other.read(masked=True)) - else: - result = function(self.read(masked=True), other) - - nodata = get_nodata_value(result.dtype) - - # open output file with updated metadata - meta = self.meta.copy() - meta.update(driver=driver, count=1, dtype=result.dtype, nodata=nodata) - - with MemoryFile() as memfile: - dst = memfile.open(**meta) - result = np.ma.filled(result, fill_value=nodata) - dst.write(result, indexes=1) - - # create RasterLayer from result - layer = RasterLayer(rasterio.band(dst, 1)) - - return layer - - def __add__(self, other): - """Implements behaviour for addition of two RasterLayers, - i.e. added_layer = layer1 + layer2 - """ - - def func(arr1, arr2): - return arr1 + arr2 - - return self._arith(func, other) - - def __sub__(self, other): - """Implements behaviour for subtraction of two RasterLayers, i.e. - subtracted_layer = layer1 - layer2 - """ - - def func(arr1, arr2): - return arr1 - arr2 - - return self._arith(func, other) - - def __mul__(self, other): - """Implements behaviour for multiplication of two RasterLayers, i.e. - product = layer1 * layer2 - """ - - def func(arr1, arr2): - return arr1 * arr2 - - return self._arith(func, other) - - def __truediv__(self, other): - """Implements behaviour for division using `/` of two RasterLayers, - i.e. div = layer1 / layer2 - """ - - def func(arr1, arr2): - return arr1 / arr2 - - return self._arith(func, other) - - def __and__(self, other): - """Implements & operator - - Equivalent to a intersection operation of self - with other, i.e. intersected = layer1 & layer2. - """ - - def func(arr1, arr2): - mask = np.logical_and(arr1, arr2).mask - arr1.mask[mask] = True - return arr1 - - return self._arith(func, other) - - def __or__(self, other): - """Implements | operator - - Fills gaps in self with pixels from other. Equivalent to a union - operation, i.e. union = layer1 | layer2. - """ - - def func(arr1, arr2): - idx = np.logical_or(arr1, arr2.mask).mask - arr1[idx] = arr2[idx] - return arr1 - - return self._arith(func, other) - - def __xor__(self, other): - """Exclusive OR using ^ - - Equivalent to a symmetrical difference where the result comprises - pixels that occur in self or other, but not both, i.e. - xor = layer1 ^ layer2. - """ - - def func(arr1, arr2): - mask = ~np.logical_xor(arr1, arr2) - idx = np.logical_or(arr1, arr2.mask).mask - arr1[idx] = arr2[idx] - arr1.mask[np.nonzero(mask)] = True - return arr1 - - return self._arith(func, other) - - def __round__(self, ndigits): - """Behaviour for round() function, i.e. round(layer)""" - - def func(arr, ndigits): - return np.round(arr, ndigits) - - func = partial(func, ndigits=ndigits) - - return self._arith(func) - - def __floor__(self): - """Rounding down to the nearest integer using math.floor(), - i.e. math.floor(layer)""" - - def func(arr): - return np.floor(arr) - - return self._arith(func) - - def __ceil__(self): - """Rounding up to the nearest integer using math.ceil(), i.e. - math.ceil(layer)""" - - def func(arr): - return np.ceil(arr) - - return self._arith(func) - - def __trunc__(self): - """Truncating to an integral using math.trunc(), i.e. - math.trunc(layer)""" - - def func(arr): - return np.trunc(arr) - - return self._arith(func) - - def __abs__(self): - """abs() function as applied to a RasterLayer, i.e. abs(layer)""" - - def func(arr): - return np.abs(arr) - - return self._arith(func) - - def __pos__(self): - """Unary positive, i.e. +layer1""" - - def func(arr): - return np.positive(arr) - - return self._arith(func) - - def __neg__(self): - """ - Unary negative, i.e. -layer1 - """ - - def func(arr): - return np.negative(arr) - - return self._arith(func) - - def read(self, **kwargs): - """Read method for a single RasterLayer. - - Reads the pixel values from a RasterLayer into a ndarray that - always will have two dimensions in the order of (rows, columns). - - Parameters - ---------- - **kwargs : named arguments that can be passed to the the - rasterio.DatasetReader.read method. - """ - if "resampling" in kwargs.keys(): - resampling_methods = [i.name for i in rasterio.enums.Resampling] - - if kwargs["resampling"] not in resampling_methods: - raise ValueError( - "Invalid resampling method. Resampling " - "method must be one of {0}:".format(resampling_methods) - ) - - kwargs["resampling"] = rasterio.enums.Resampling[kwargs["resampling"]] - - return self.ds.read(indexes=self.bidx, **kwargs) - - def seek(self, offset, whence=None): - return self - - def tell(self): - return self - - def write(self, file_path, driver="GTiff", dtype=None, nodata=None, **kwargs): - """Write method for a single RasterLayer. - - Parameters - ---------- - file_path : str (opt) - File path to save the dataset. - - driver : str - GDAL-compatible driver used for the file format. - - dtype : str (opt) - Numpy dtype used for the file. If omitted then the - RasterLayer's dtype is used. - - nodata : any number (opt) - A value used to represent the nodata pixels. If omitted - then the RasterLayer's nodata value is used (if assigned - already). - - kwargs : opt - Optional named arguments to pass to the format drivers. - For example can be `compress="deflate"` to add compression. - - Returns - ------- - pyspatialml.RasterLayer - """ - if dtype is None: - dtype = self.dtype - - if nodata is None: - nodata = get_nodata_value(dtype) - - meta = self.ds.meta - meta["driver"] = driver - meta["nodata"] = nodata - meta["dtype"] = dtype - meta.update(kwargs) - - # mask any nodata values - arr = np.ma.masked_equal(self.read(), self.nodata) - arr = arr.filled(fill_value=nodata) - - # write to file - with rasterio.open(file_path, mode="w", **meta) as dst: - dst.write(arr.astype(dtype), 1) - - src = rasterio.open(file_path) - band = rasterio.band(src, 1) - layer = RasterLayer(band) - - return layer - - def _extract_by_indices(self, rows, cols): - """Spatial query of Raster object (by-band)""" - - X = np.ma.zeros((len(rows), self.count), dtype="float32") - arr = self.read(masked=True) - X[:, 0] = arr[rows, cols] - - return X +from functools import partial + +import os +import re +import numpy as np +import rasterio +from rasterio.io import MemoryFile + +from ._plotting import RasterLayerPlotMixin +from ._rasterstats import RasterLayerStatsMixin +from ._utils import get_nodata_value + + +class RasterLayer(RasterLayerStatsMixin, RasterLayerPlotMixin): + """Represents a single raster band derived from a single or + multi-band raster dataset + + Simple wrapper around a rasterio.Band object with additional + methods. Used because the Rasterio.Band.ds.read method reads + all bands from a multi-band dataset, whereas the RasterLayer read + method only reads a single band. + + Methods encapsulated in RasterLayer objects represent those that + typically would only be applied to a single-band of a raster, i.e. + sieve-clump, distance to non-NaN pixels, or arithmetic operations + on individual layers. + + Attributes + ---------- + bidx : int + The band index of the RasterLayer within the file dataset. + + dtype : str + The data type of the RasterLayer. + + ds : rasterio.band + The underlying rasterio.band object. + + name : str + A syntactically valid name for the RasterLayer. + + file : str + The file path to the dataset. + + nodata : any number + The number that is used to represent nodata pixels in the + RasterLayer. + + driver : str + The name of the GDAL format driver. + + meta : dict + A python dict storing the RasterLayer metadata. + + transform : affine.Affine object + The affine transform parameters. + + count : int + Number of layers; always equal to 1. + + shape: tuple + Shape of RasterLayer in (rows, columns) + + width, height: int + The width (cols) and height (rows) of the dataset. + + bounds : BoundingBox named tuple + A named tuple with left, bottom, right and top coordinates of + the dataset. + + cmap : str + The name of matplotlib map, or a custom + matplotlib.cm.LinearSegmentedColormap or ListedColormap object. + + norm : matplotlib.colors.Normalize (opt) + A matplotlib.colors.Normalize to apply to the RasterLayer. + This overides the norm attribute of the RasterLayer. + """ + + def __init__(self, band): + """Initiate a RasterLayer object + + Parameters + ---------- + band : a rasterio.Band object + """ + self.bidx = band.bidx + self.dtype = band.dtype + self.ds = band.ds + + if len(band.ds.files) > 0: + description = band.ds.descriptions[band.bidx-1] + if description is not None: + layer_name = self._make_name(band.ds.descriptions[band.bidx-1]) + else: + layer_name = self._make_name(band.ds.files[0]) + + self.name = layer_name + self.file = band.ds.files[0] + + else: + self.name = "in_memory" + self.file = None + + self.nodata = band.ds.nodata + self.driver = band.ds.meta["driver"] + self.meta = band.ds.meta + self.transform = band.ds.transform + self.crs = band.ds.crs + self.count = 1 + self.shape = band.shape + self.width = band.ds.width + self.height = band.ds.height + self.bounds = band.ds.bounds + self.in_memory = False + + self.cmap = "viridis" + self.norm = None + self.categorical = False + + @staticmethod + def _make_name(name): + """Converts a file basename to a valid class attribute name. + + Parameters + ---------- + name : str + File basename for converting to a valid class attribute name. + + Returns + ------- + valid_name : str + Syntactically correct name of layer so that it can form a class + instance attribute. + """ + basename = os.path.basename(name) + sans_ext = os.path.splitext(basename)[0] + + valid_name = sans_ext.replace(" ", "_").replace("-", "_").replace(".", "_") + + if valid_name[0].isdigit(): + valid_name = "x" + valid_name + + valid_name = re.sub(r"[\[\]\(\)\{\}\;]", "", valid_name) + valid_name = re.sub(r"_+", "_", valid_name) + + return valid_name + + def close(self): + self.ds.close() + + def _arith(self, function, other=None): + """General method for performing arithmetic operations on + RasterLayer objects + + Parameters + ---------- + function : function + Custom function that takes either one or two arrays, and + returns a single array following a pre-defined calculation. + + other : pyspatialml.RasterLayer (optional, default None) + If not specified, then a `function` should be provided that + performs a calculation using only the selected RasterLayer. + If `other` is specified, then a `function` should be + supplied that takes two ndarrays as arguments and performs a + calculation using both layers, i.e. layer1 - layer2. + + Returns + ------- + pyspatialml.RasterLayer + Returns a single RasterLayer containing the calculated + result. + """ + + driver = self.driver + + # if other is a RasterLayer then use the read method to get the + # array, otherwise assume other is a scalar or array + if isinstance(other, RasterLayer): + result = function(self.read(masked=True), other.read(masked=True)) + else: + result = function(self.read(masked=True), other) + + nodata = get_nodata_value(result.dtype) + + # open output file with updated metadata + meta = self.meta.copy() + meta.update(driver=driver, count=1, dtype=result.dtype, nodata=nodata) + + with MemoryFile() as memfile: + dst = memfile.open(**meta) + result = np.ma.filled(result, fill_value=nodata) + dst.write(result, indexes=1) + + # create RasterLayer from result + layer = RasterLayer(rasterio.band(dst, 1)) + + return layer + + def __add__(self, other): + """Implements behaviour for addition of two RasterLayers, + i.e. added_layer = layer1 + layer2 + """ + + def func(arr1, arr2): + return arr1 + arr2 + + return self._arith(func, other) + + def __sub__(self, other): + """Implements behaviour for subtraction of two RasterLayers, i.e. + subtracted_layer = layer1 - layer2 + """ + + def func(arr1, arr2): + return arr1 - arr2 + + return self._arith(func, other) + + def __mul__(self, other): + """Implements behaviour for multiplication of two RasterLayers, i.e. + product = layer1 * layer2 + """ + + def func(arr1, arr2): + return arr1 * arr2 + + return self._arith(func, other) + + def __truediv__(self, other): + """Implements behaviour for division using `/` of two RasterLayers, + i.e. div = layer1 / layer2 + """ + + def func(arr1, arr2): + return arr1 / arr2 + + return self._arith(func, other) + + def __and__(self, other): + """Implements & operator + + Equivalent to a intersection operation of self + with other, i.e. intersected = layer1 & layer2. + """ + + def func(arr1, arr2): + mask = np.logical_and(arr1, arr2).mask + arr1.mask[mask] = True + return arr1 + + return self._arith(func, other) + + def __or__(self, other): + """Implements | operator + + Fills gaps in self with pixels from other. Equivalent to a union + operation, i.e. union = layer1 | layer2. + """ + + def func(arr1, arr2): + idx = np.logical_or(arr1, arr2.mask).mask + arr1[idx] = arr2[idx] + return arr1 + + return self._arith(func, other) + + def __xor__(self, other): + """Exclusive OR using ^ + + Equivalent to a symmetrical difference where the result comprises + pixels that occur in self or other, but not both, i.e. + xor = layer1 ^ layer2. + """ + + def func(arr1, arr2): + mask = ~np.logical_xor(arr1, arr2) + idx = np.logical_or(arr1, arr2.mask).mask + arr1[idx] = arr2[idx] + arr1.mask[np.nonzero(mask)] = True + return arr1 + + return self._arith(func, other) + + def __round__(self, ndigits): + """Behaviour for round() function, i.e. round(layer)""" + + def func(arr, ndigits): + return np.round(arr, ndigits) + + func = partial(func, ndigits=ndigits) + + return self._arith(func) + + def __floor__(self): + """Rounding down to the nearest integer using math.floor(), + i.e. math.floor(layer)""" + + def func(arr): + return np.floor(arr) + + return self._arith(func) + + def __ceil__(self): + """Rounding up to the nearest integer using math.ceil(), i.e. + math.ceil(layer)""" + + def func(arr): + return np.ceil(arr) + + return self._arith(func) + + def __trunc__(self): + """Truncating to an integral using math.trunc(), i.e. + math.trunc(layer)""" + + def func(arr): + return np.trunc(arr) + + return self._arith(func) + + def __abs__(self): + """abs() function as applied to a RasterLayer, i.e. abs(layer)""" + + def func(arr): + return np.abs(arr) + + return self._arith(func) + + def __pos__(self): + """Unary positive, i.e. +layer1""" + + def func(arr): + return np.positive(arr) + + return self._arith(func) + + def __neg__(self): + """ + Unary negative, i.e. -layer1 + """ + + def func(arr): + return np.negative(arr) + + return self._arith(func) + + def read(self, **kwargs): + """Read method for a single RasterLayer. + + Reads the pixel values from a RasterLayer into a ndarray that + always will have two dimensions in the order of (rows, columns). + + Parameters + ---------- + **kwargs : named arguments that can be passed to the the + rasterio.DatasetReader.read method. + """ + if "resampling" in kwargs.keys(): + resampling_methods = [i.name for i in rasterio.enums.Resampling] + + if kwargs["resampling"] not in resampling_methods: + raise ValueError( + "Invalid resampling method. Resampling " + "method must be one of {0}:".format(resampling_methods) + ) + + kwargs["resampling"] = rasterio.enums.Resampling[kwargs["resampling"]] + + return self.ds.read(indexes=self.bidx, **kwargs) + + def seek(self, offset, whence=None): + return self + + def tell(self): + return self + + def write(self, file_path, driver="GTiff", dtype=None, nodata=None, **kwargs): + """Write method for a single RasterLayer. + + Parameters + ---------- + file_path : str (opt) + File path to save the dataset. + + driver : str + GDAL-compatible driver used for the file format. + + dtype : str (opt) + Numpy dtype used for the file. If omitted then the + RasterLayer's dtype is used. + + nodata : any number (opt) + A value used to represent the nodata pixels. If omitted + then the RasterLayer's nodata value is used (if assigned + already). + + kwargs : opt + Optional named arguments to pass to the format drivers. + For example can be `compress="deflate"` to add compression. + + Returns + ------- + pyspatialml.RasterLayer + """ + if dtype is None: + dtype = self.dtype + + if nodata is None: + nodata = get_nodata_value(dtype) + + meta = self.ds.meta + meta["driver"] = driver + meta["nodata"] = nodata + meta["dtype"] = dtype + meta.update(kwargs) + + # mask any nodata values + arr = np.ma.masked_equal(self.read(), self.nodata) + arr = arr.filled(fill_value=nodata) + + # write to file + with rasterio.open(file_path, mode="w", **meta) as dst: + dst.write(arr.astype(dtype), 1) + + src = rasterio.open(file_path) + band = rasterio.band(src, 1) + layer = RasterLayer(band) + + return layer + + def _extract_by_indices(self, rows, cols): + """Spatial query of Raster object (by-band)""" + + X = np.ma.zeros((len(rows), self.count), dtype="float32") + arr = self.read(masked=True) + X[:, 0] = arr[rows, cols] + + return X diff --git a/pyspatialml/transformers.py b/pyspatialml/transformers.py index aa18a42..72ad19c 100644 --- a/pyspatialml/transformers.py +++ b/pyspatialml/transformers.py @@ -1,429 +1,429 @@ -import numpy as np -from scipy.spatial.distance import cdist -from scipy.spatial import cKDTree -from sklearn.base import BaseEstimator, TransformerMixin -from sklearn.neighbors import NearestNeighbors -from sklearn.preprocessing import Normalizer -from sklearn.utils.extmath import weighted_mode - - -class KNNTransformer(BaseEstimator, TransformerMixin): - """Transformer to generate new lag features by weighted aggregation - of K-neighboring observations. - - A lag transformer uses a weighted mean/mode of the values of the - K-neighboring observations to generate new lagged features. The - weighted mean/mode of the surrounding observations are appended - as a new feature to the right-most column in the training data. - - The K-neighboring observations are determined using the distance - metric specified in the `metric` argument. The default metric is - minkowski, and with p=2 is equivalent to the standard Euclidean - metric. - - Parameters - ---------- - n_neighbors : int, default = 7 - Number of neighbors to use by default for kneighbors queries. - - weights : {‘uniform’, ‘distance’} or callable, default=’distance’ - Weight function used in prediction. Possible values: - - - ‘uniform’ : uniform weights. All points in each - neighborhood are weighted equally. - - ‘distance’ : weight points by the inverse of their - distance. In this case, closer neighbors of a query - point will have a greater influence than neighbors - which are further away. - - [callable] : a user-defined function which accepts an - array of distances, and returns an array of the same - shape containing the weights. - - measure : {'mean', 'mode'} - Function that is used to apply the weights to `y`. Use 'mean' - if the target variable is continuous and 'mode' if the target - variable is discrete. - - radius : float, default=1.0 - Range of parameter space to use by default for radius_neighbors - queries. - - algorithm: {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’ - Algorithm used to compute the nearest neighbors: - - - ‘ball_tree’ will use BallTree - - ‘kd_tree’ will use KDTree - - ‘brute’ will use a brute-force search. - - ‘auto’ will attempt to decide the most appropriate - algorithm based on the values passed to fit method. - - Note: fitting on sparse input will override the setting - of this parameter, using brute force. - - leaf_size : int, default=30 - Leaf size passed to BallTree or KDTree. This can affect the - speed of the construction and query, as well as the memory - required to store the tree. The optimal value depends on the - nature of the problem. - - metric : str or callable, default=’minkowski’ - The distance metric to use for the tree. The default metric is - minkowski, and with p=2 is equivalent to the standard - Euclidean metric. See the documentation of DistanceMetric for - a list of available metrics. If metric is “precomputed”, X is - assumed to be a distance matrix and must be square during fit. - X may be a sparse graph, in which case only “nonzero” elements - may be considered neighbors. - - p : int, default=2 - Parameter for the Minkowski metric from - sklearn.metrics.pairwise.pairwise_distances. When p = 1, this - is equivalent to using manhattan_distance (l1), and - euclidean_distance (l2) for p = 2. For arbitrary p, - minkowski_distance (l_p) is used. - - normalize : bool, default=True - Whether to normalize the inputs using - sklearn.preprocessing.Normalizer - - metric_params : dict, default=None - Additional keyword arguments for the metric function. - - kernel_params : dict, default=None - Additional keyword arguments to pass to a custom kernel - function. - - n_jobs : int, default=None - The number of parallel jobs to run for neighbors search. None - means 1 unless in a joblib.parallel_backend context. -1 means - using all processors. See Glossary for more details. - """ - - def __init__( - self, - n_neighbors=7, - weights="distance", - measure="mean", - radius=1.0, - algorithm="auto", - leaf_size=30, - metric="minkowski", - p=2, - normalize=True, - metric_params=None, - kernel_params=None, - n_jobs=1, - ): - - self.n_neighbors = n_neighbors - self.weights = weights - self.measure = measure - self.radius = radius - self.algorithm = algorithm - self.leaf_size = leaf_size - self.metric = metric - self.p = p - self.metric_params = metric_params - self.kernel_params = kernel_params - self.normalize = normalize - self.n_jobs = n_jobs - - self.knn = NearestNeighbors( - n_neighbors=self.n_neighbors, - radius=self.radius, - algorithm=self.algorithm, - leaf_size=self.leaf_size, - metric=self.metric, - p=self.p, - metric_params=self.metric_params, - n_jobs=self.n_jobs, - ) - - self.y_ = None - - def fit(self, X, y=None): - """Fit the base_estimator with features from X - {n_samples, n_features} and with an additional spatially lagged - variable added to the right-most column of the training data. - - During fitting, the k-neighbors to each training point are - used to estimate the spatial lag component. The training point - is not included in the calculation, i.e. the training point is - not considered its own neighbor. - - Parameters - ---------- - X : array-like of sample {n_samples, n_features} using for model - fitting The training input samples - - y : array-like of shape (n_samples,) - The target values (class labels in classification, real - numbers in regression). - """ - # some checks - if self.kernel_params is None: - self.kernel_params = {} - - if y.ndim == 1: - self.n_outputs_ = 1 - else: - self.n_outputs_ = y.shape[1] - - # fit knn and get values of neighbors - if self.normalize is True: - scaler = Normalizer() - X = scaler.fit_transform(X) - self.scaler_ = scaler - - self.knn.fit(X) - self.y_ = y.copy() - - return self - - def transform(self, X, y=None): - """Transform method for spatial lag models. - - Augments new observations with a spatial lag variable created - from a weighted mean/mode (regression/classification) of - k-neighboring observations. - - Parameters - ---------- - X : array-like of sample {n_samples, n_features} - New samples for the prediction. - - y : None - Not used. - """ - # get distances from training points to new data - if self.normalize is True: - X = self.scaler_.transform(X) - - neighbor_dist, neighbor_ids = self.knn.kneighbors(X=X) - - # mask zero distances - neighbor_dist = np.ma.masked_equal(neighbor_dist, 0) - - # get values of closest training points to new data - neighbor_vals = np.array([self.y_[i] for i in neighbor_ids]) - - # mask neighbor values with zero distances - mask = neighbor_dist.mask - - if mask.all() == False: - mask = np.zeros(neighbor_dist.shape, dtype=bool) - mask[:] = False - - if neighbor_vals.ndim == 2: - neighbor_vals = np.ma.masked_array(neighbor_vals, mask) - else: - n_outputs = neighbor_vals.shape[2] - mask = np.repeat(mask[:, :, np.newaxis], n_outputs, axis=2) - neighbor_vals = np.ma.masked_array(neighbor_vals, mask=mask) - - # calculated weighted means - if self.weights == "distance": - new_X = self._distance_weighting(neighbor_vals, neighbor_dist) - - elif self.weights == "uniform": - new_X = self._uniform_weighting(neighbor_vals) - - elif callable(self.weights): - new_X = self._custom_weighting(neighbor_vals, neighbor_dist) - - return np.column_stack((X, new_X)) - - def _apply_weights(self, neighbor_vals, neighbor_weights): - # weighted mean/mode of neighbors for a single regression target - if neighbor_vals.ndim == 2: - if self.measure == "mean": - X = np.ma.average(neighbor_vals, weights=neighbor_weights, axis=1) - else: - X, _ = weighted_mode(neighbor_vals, neighbor_weights, axis=1) - - # weighted mean of neighbors for a multi-target regression - # neighbor_vals = (n_samples, n_neighbors, n_targets) - else: - X = np.zeros((neighbor_vals.shape[0], neighbor_vals.shape[2])) - - if self.measure == "mean": - for i in range(neighbor_vals.shape[-1]): - X[:, i] = np.ma.average( - neighbor_vals[:, :, i], weights=neighbor_weights, axis=1 - ) - else: - for i in range(neighbor_vals.shape[-1]): - X[:, i], _ = weighted_mode( - neighbor_vals[:, :, i], neighbor_weights, axis=1 - ) - - return X - - def _distance_weighting(self, neighbor_vals, neighbor_dist): - weights = 1 / neighbor_dist - return self._apply_weights(neighbor_vals, weights) - - def _uniform_weighting(self, neighbor_vals): - weights = np.ones((neighbor_vals.shape[0], neighbor_vals.shape[0])) - return self._apply_weights(neighbor_vals, weights) - - def _custom_weighting(self, neighbor_vals, neighbor_dist): - weights = self.weights(neighbor_dist, **self.kernel_params) - return self._apply_weights(neighbor_vals, weights) - - def _distance_weighting(self, neighbor_vals, neighbor_dist): - weights = 1 / neighbor_dist - return self._apply_weights(neighbor_vals, weights) - - def _uniform_weighting(self, neighbor_vals): - weights = np.ones((neighbor_vals.shape[0], neighbor_vals.shape[0])) - return self._apply_weights(neighbor_vals, weights) - - def _custom_weighting(self, neighbor_vals, neighbor_dist): - weights = self.weights(neighbor_dist, **self.kernel_params) - return self._apply_weights(neighbor_vals, weights) - - -class GeoDistTransformer(BaseEstimator, TransformerMixin): - """Transformer to add new features based on geographical distances - to reference locations. - - Parameters - ---------- - refs : ndarray - Array of coordinates of reference locations in - (m, n-dimensional) order, such as {n_locations, - x_coordinates, y_coordinates, ...} for as many dimensions as - required. For example to calculate distances to a single x,y,z - location: - - refs = [-57.345, -110.134, 1012] - - And to calculate distances to three x,y reference locations: - - refs = [ - [-57.345, -110.134], - [-56.345, -109.123], - [-58.534, -112.123] - ] - - The supplied array has to have at least x,y coordinates with a - (1, 2) shape for a single location. - - minimum : bool, default is False - Optionally calculate the minimum distance to the combined - reference locations, resulting in a single new feature, - rather than a new feature for each individual reference - location. - - log : bool (opt), default=False - Optionally log-transform the distance measures. - - Returns - ------- - X_new : ndarray - Array of shape (n_samples, n_features) with new geodistance - features appended to the right-most columns of the array. - """ - - def __init__(self, refs, minimum=False, log=False): - self.refs = refs - self.log = log - self.refs_ = None - self.minimum = minimum - - def fit(self, X, y=None): - self.refs_ = np.asarray(self.refs) - - if self.refs_.ndim < 2: - raise ValueError( - "`refs` has to be a m,n-dimensional array with at least two dimensions" - ) - - return self - - def transform(self, X, y=None): - if self.minimum is False: - dists = cdist(self.refs_, X).transpose() - - if self.minimum is True: - tree = cKDTree(self.refs_) - dists, _ = tree.query(X) - - if self.log is True: - dists = np.log(dists) - - return np.column_stack((X, dists)) - - -class AspectTransformer(BaseEstimator, TransformerMixin): - """Transformer to decompose aspect maps into northerness and easterness""" - - def __init__(self): - self._quadrants = None - self._reverse = np.array([0.0, 360.0]) - - def _dir_from_comp(self, X): - return np.rad2deg(np.arctan2(X[:, 1], X[:, 0])) - - def fit(self, X, y=None): - return self - - def fit_transform(self, X, y=None): - return self.transform(X, y) - - def transform(self, X, y=None): - """Takes a vector of floating point numbers, assumed to be aspect in degrees - and returns an array with two dimensions with the strength of the easterly and - northernly direction - - Parameters - ---------- - X : array-like of sample {n_samples, n_features} - New samples for the prediction. - - y : None - Not used. - - Returns - ------- - ndarray : 2d array with the sin and cosine components of the original - data. - """ - # ensure that X is a ndarray - if isinstance(X, list): - X = np.asarray(X) - - # store quadrant so that inverse can be found - condlist = [np.logical_and(X >= 0, X <= 180), np.logical_and(X > 180, X < 360)] - choicelist = np.arange(0, 2) - self._quadrants = np.select(condlist, choicelist) - - radians = np.deg2rad(X) - easterness = np.cos(radians) - northerness = np.sin(radians) - - return np.column_stack([easterness, northerness]) - - def inverse_transform(self, X, y=None): - """Takes a vector with two columns containing the strength of the easterly and - northernly directions and returns a array with a single dimension with the - azimuth in degrees - - Because the quadrant is not known, this function only returns the azimuth - relative to a northernly direction - - Parameters - ---------- - X : array-like of sample {n_samples, n_features} - New samples for the prediction. - - y : None - Not used. - - Returns - ------- - ndarray : 2d array with the azimuth. - """ - inverse = self._dir_from_comp(X) - inverse = np.abs(inverse + self._reverse[self._quadrants]) - return inverse +import numpy as np +from scipy.spatial.distance import cdist +from scipy.spatial import cKDTree +from sklearn.base import BaseEstimator, TransformerMixin +from sklearn.neighbors import NearestNeighbors +from sklearn.preprocessing import Normalizer +from sklearn.utils.extmath import weighted_mode + + +class KNNTransformer(BaseEstimator, TransformerMixin): + """Transformer to generate new lag features by weighted aggregation + of K-neighboring observations. + + A lag transformer uses a weighted mean/mode of the values of the + K-neighboring observations to generate new lagged features. The + weighted mean/mode of the surrounding observations are appended + as a new feature to the right-most column in the training data. + + The K-neighboring observations are determined using the distance + metric specified in the `metric` argument. The default metric is + minkowski, and with p=2 is equivalent to the standard Euclidean + metric. + + Parameters + ---------- + n_neighbors : int, default = 7 + Number of neighbors to use by default for kneighbors queries. + + weights : {‘uniform’, ‘distance’} or callable, default=’distance’ + Weight function used in prediction. Possible values: + + - ‘uniform’ : uniform weights. All points in each + neighborhood are weighted equally. + - ‘distance’ : weight points by the inverse of their + distance. In this case, closer neighbors of a query + point will have a greater influence than neighbors + which are further away. + - [callable] : a user-defined function which accepts an + array of distances, and returns an array of the same + shape containing the weights. + + measure : {'mean', 'mode'} + Function that is used to apply the weights to `y`. Use 'mean' + if the target variable is continuous and 'mode' if the target + variable is discrete. + + radius : float, default=1.0 + Range of parameter space to use by default for radius_neighbors + queries. + + algorithm: {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’ + Algorithm used to compute the nearest neighbors: + + - ‘ball_tree’ will use BallTree + - ‘kd_tree’ will use KDTree + - ‘brute’ will use a brute-force search. + - ‘auto’ will attempt to decide the most appropriate + algorithm based on the values passed to fit method. + - Note: fitting on sparse input will override the setting + of this parameter, using brute force. + + leaf_size : int, default=30 + Leaf size passed to BallTree or KDTree. This can affect the + speed of the construction and query, as well as the memory + required to store the tree. The optimal value depends on the + nature of the problem. + + metric : str or callable, default=’minkowski’ + The distance metric to use for the tree. The default metric is + minkowski, and with p=2 is equivalent to the standard + Euclidean metric. See the documentation of DistanceMetric for + a list of available metrics. If metric is “precomputed”, X is + assumed to be a distance matrix and must be square during fit. + X may be a sparse graph, in which case only “nonzero” elements + may be considered neighbors. + + p : int, default=2 + Parameter for the Minkowski metric from + sklearn.metrics.pairwise.pairwise_distances. When p = 1, this + is equivalent to using manhattan_distance (l1), and + euclidean_distance (l2) for p = 2. For arbitrary p, + minkowski_distance (l_p) is used. + + normalize : bool, default=True + Whether to normalize the inputs using + sklearn.preprocessing.Normalizer + + metric_params : dict, default=None + Additional keyword arguments for the metric function. + + kernel_params : dict, default=None + Additional keyword arguments to pass to a custom kernel + function. + + n_jobs : int, default=None + The number of parallel jobs to run for neighbors search. None + means 1 unless in a joblib.parallel_backend context. -1 means + using all processors. See Glossary for more details. + """ + + def __init__( + self, + n_neighbors=7, + weights="distance", + measure="mean", + radius=1.0, + algorithm="auto", + leaf_size=30, + metric="minkowski", + p=2, + normalize=True, + metric_params=None, + kernel_params=None, + n_jobs=1, + ): + + self.n_neighbors = n_neighbors + self.weights = weights + self.measure = measure + self.radius = radius + self.algorithm = algorithm + self.leaf_size = leaf_size + self.metric = metric + self.p = p + self.metric_params = metric_params + self.kernel_params = kernel_params + self.normalize = normalize + self.n_jobs = n_jobs + + self.knn = NearestNeighbors( + n_neighbors=self.n_neighbors, + radius=self.radius, + algorithm=self.algorithm, + leaf_size=self.leaf_size, + metric=self.metric, + p=self.p, + metric_params=self.metric_params, + n_jobs=self.n_jobs, + ) + + self.y_ = None + + def fit(self, X, y=None): + """Fit the base_estimator with features from X + {n_samples, n_features} and with an additional spatially lagged + variable added to the right-most column of the training data. + + During fitting, the k-neighbors to each training point are + used to estimate the spatial lag component. The training point + is not included in the calculation, i.e. the training point is + not considered its own neighbor. + + Parameters + ---------- + X : array-like of sample {n_samples, n_features} using for model + fitting The training input samples + + y : array-like of shape (n_samples,) + The target values (class labels in classification, real + numbers in regression). + """ + # some checks + if self.kernel_params is None: + self.kernel_params = {} + + if y.ndim == 1: + self.n_outputs_ = 1 + else: + self.n_outputs_ = y.shape[1] + + # fit knn and get values of neighbors + if self.normalize is True: + scaler = Normalizer() + X = scaler.fit_transform(X) + self.scaler_ = scaler + + self.knn.fit(X) + self.y_ = y.copy() + + return self + + def transform(self, X, y=None): + """Transform method for spatial lag models. + + Augments new observations with a spatial lag variable created + from a weighted mean/mode (regression/classification) of + k-neighboring observations. + + Parameters + ---------- + X : array-like of sample {n_samples, n_features} + New samples for the prediction. + + y : None + Not used. + """ + # get distances from training points to new data + if self.normalize is True: + X = self.scaler_.transform(X) + + neighbor_dist, neighbor_ids = self.knn.kneighbors(X=X) + + # mask zero distances + neighbor_dist = np.ma.masked_equal(neighbor_dist, 0) + + # get values of closest training points to new data + neighbor_vals = np.array([self.y_[i] for i in neighbor_ids]) + + # mask neighbor values with zero distances + mask = neighbor_dist.mask + + if mask.all() == False: + mask = np.zeros(neighbor_dist.shape, dtype=bool) + mask[:] = False + + if neighbor_vals.ndim == 2: + neighbor_vals = np.ma.masked_array(neighbor_vals, mask) + else: + n_outputs = neighbor_vals.shape[2] + mask = np.repeat(mask[:, :, np.newaxis], n_outputs, axis=2) + neighbor_vals = np.ma.masked_array(neighbor_vals, mask=mask) + + # calculated weighted means + if self.weights == "distance": + new_X = self._distance_weighting(neighbor_vals, neighbor_dist) + + elif self.weights == "uniform": + new_X = self._uniform_weighting(neighbor_vals) + + elif callable(self.weights): + new_X = self._custom_weighting(neighbor_vals, neighbor_dist) + + return np.column_stack((X, new_X)) + + def _apply_weights(self, neighbor_vals, neighbor_weights): + # weighted mean/mode of neighbors for a single regression target + if neighbor_vals.ndim == 2: + if self.measure == "mean": + X = np.ma.average(neighbor_vals, weights=neighbor_weights, axis=1) + else: + X, _ = weighted_mode(neighbor_vals, neighbor_weights, axis=1) + + # weighted mean of neighbors for a multi-target regression + # neighbor_vals = (n_samples, n_neighbors, n_targets) + else: + X = np.zeros((neighbor_vals.shape[0], neighbor_vals.shape[2])) + + if self.measure == "mean": + for i in range(neighbor_vals.shape[-1]): + X[:, i] = np.ma.average( + neighbor_vals[:, :, i], weights=neighbor_weights, axis=1 + ) + else: + for i in range(neighbor_vals.shape[-1]): + X[:, i], _ = weighted_mode( + neighbor_vals[:, :, i], neighbor_weights, axis=1 + ) + + return X + + def _distance_weighting(self, neighbor_vals, neighbor_dist): + weights = 1 / neighbor_dist + return self._apply_weights(neighbor_vals, weights) + + def _uniform_weighting(self, neighbor_vals): + weights = np.ones((neighbor_vals.shape[0], neighbor_vals.shape[0])) + return self._apply_weights(neighbor_vals, weights) + + def _custom_weighting(self, neighbor_vals, neighbor_dist): + weights = self.weights(neighbor_dist, **self.kernel_params) + return self._apply_weights(neighbor_vals, weights) + + def _distance_weighting(self, neighbor_vals, neighbor_dist): + weights = 1 / neighbor_dist + return self._apply_weights(neighbor_vals, weights) + + def _uniform_weighting(self, neighbor_vals): + weights = np.ones((neighbor_vals.shape[0], neighbor_vals.shape[0])) + return self._apply_weights(neighbor_vals, weights) + + def _custom_weighting(self, neighbor_vals, neighbor_dist): + weights = self.weights(neighbor_dist, **self.kernel_params) + return self._apply_weights(neighbor_vals, weights) + + +class GeoDistTransformer(BaseEstimator, TransformerMixin): + """Transformer to add new features based on geographical distances + to reference locations. + + Parameters + ---------- + refs : ndarray + Array of coordinates of reference locations in + (m, n-dimensional) order, such as {n_locations, + x_coordinates, y_coordinates, ...} for as many dimensions as + required. For example to calculate distances to a single x,y,z + location: + + refs = [-57.345, -110.134, 1012] + + And to calculate distances to three x,y reference locations: + + refs = [ + [-57.345, -110.134], + [-56.345, -109.123], + [-58.534, -112.123] + ] + + The supplied array has to have at least x,y coordinates with a + (1, 2) shape for a single location. + + minimum : bool, default is False + Optionally calculate the minimum distance to the combined + reference locations, resulting in a single new feature, + rather than a new feature for each individual reference + location. + + log : bool (opt), default=False + Optionally log-transform the distance measures. + + Returns + ------- + X_new : ndarray + Array of shape (n_samples, n_features) with new geodistance + features appended to the right-most columns of the array. + """ + + def __init__(self, refs, minimum=False, log=False): + self.refs = refs + self.log = log + self.refs_ = None + self.minimum = minimum + + def fit(self, X, y=None): + self.refs_ = np.asarray(self.refs) + + if self.refs_.ndim < 2: + raise ValueError( + "`refs` has to be a m,n-dimensional array with at least two dimensions" + ) + + return self + + def transform(self, X, y=None): + if self.minimum is False: + dists = cdist(self.refs_, X).transpose() + + if self.minimum is True: + tree = cKDTree(self.refs_) + dists, _ = tree.query(X) + + if self.log is True: + dists = np.log(dists) + + return np.column_stack((X, dists)) + + +class AspectTransformer(BaseEstimator, TransformerMixin): + """Transformer to decompose aspect maps into northerness and easterness""" + + def __init__(self): + self._quadrants = None + self._reverse = np.array([0.0, 360.0]) + + def _dir_from_comp(self, X): + return np.rad2deg(np.arctan2(X[:, 1], X[:, 0])) + + def fit(self, X, y=None): + return self + + def fit_transform(self, X, y=None): + return self.transform(X, y) + + def transform(self, X, y=None): + """Takes a vector of floating point numbers, assumed to be aspect in degrees + and returns an array with two dimensions with the strength of the easterly and + northernly direction + + Parameters + ---------- + X : array-like of sample {n_samples, n_features} + New samples for the prediction. + + y : None + Not used. + + Returns + ------- + ndarray : 2d array with the sin and cosine components of the original + data. + """ + # ensure that X is a ndarray + if isinstance(X, list): + X = np.asarray(X) + + # store quadrant so that inverse can be found + condlist = [np.logical_and(X >= 0, X <= 180), np.logical_and(X > 180, X < 360)] + choicelist = np.arange(0, 2) + self._quadrants = np.select(condlist, choicelist) + + radians = np.deg2rad(X) + easterness = np.cos(radians) + northerness = np.sin(radians) + + return np.column_stack([easterness, northerness]) + + def inverse_transform(self, X, y=None): + """Takes a vector with two columns containing the strength of the easterly and + northernly directions and returns a array with a single dimension with the + azimuth in degrees + + Because the quadrant is not known, this function only returns the azimuth + relative to a northernly direction + + Parameters + ---------- + X : array-like of sample {n_samples, n_features} + New samples for the prediction. + + y : None + Not used. + + Returns + ------- + ndarray : 2d array with the azimuth. + """ + inverse = self._dir_from_comp(X) + inverse = np.abs(inverse + self._reverse[self._quadrants]) + return inverse diff --git a/pyspatialml/vector.py b/pyspatialml/vector.py index c2055d0..2dfa1de 100644 --- a/pyspatialml/vector.py +++ b/pyspatialml/vector.py @@ -1,61 +1,61 @@ -import random - -from scipy.cluster.hierarchy import cut_tree, linkage -from shapely.geometry import Point - - -def filter_points(gdf, min_dist=0, remove="first"): - """Filter points in geodataframe using a minimum distance buffer. - - Parameters - ---------- - gdf : Geopandas GeoDataFrame - Containing point geometries. - - min_dist : int or float, optional (default=0) - Minimum distance by which to filter out closely spaced points. - - remove : str, optional (default='first') - Optionally choose to remove 'first' occurrences or 'last' - occurrences. - - Returns - ------- - xy : 2d array-like - Numpy array filtered coordinates - """ - xy = gdf.geometry.bounds.iloc[:, 0:2] - - Z = linkage(xy, "complete") - tree_thres = cut_tree(Z, height=min_dist) - gdf["tree_thres"] = tree_thres - - if remove == "first": - gdf = gdf.groupby(by="tree_thres").first() - - elif remove == "last": - gdf = gdf.groupby(by="tree_thres").last() - - return gdf - - -def get_random_point_in_polygon(poly): - """Generates random shapely Point geometry objects within a single - shapely Polygon object. - - Parameters - ---------- - poly : Shapely Polygon object - - Returns - ------- - p : Shapely Point object - """ - - (minx, miny, maxx, maxy) = poly.bounds - - while True: - p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy)) - - if poly.contains(p): - return p +import random + +from scipy.cluster.hierarchy import cut_tree, linkage +from shapely.geometry import Point + + +def filter_points(gdf, min_dist=0, remove="first"): + """Filter points in geodataframe using a minimum distance buffer. + + Parameters + ---------- + gdf : Geopandas GeoDataFrame + Containing point geometries. + + min_dist : int or float, optional (default=0) + Minimum distance by which to filter out closely spaced points. + + remove : str, optional (default='first') + Optionally choose to remove 'first' occurrences or 'last' + occurrences. + + Returns + ------- + xy : 2d array-like + Numpy array filtered coordinates + """ + xy = gdf.geometry.bounds.iloc[:, 0:2] + + Z = linkage(xy, "complete") + tree_thres = cut_tree(Z, height=min_dist) + gdf["tree_thres"] = tree_thres + + if remove == "first": + gdf = gdf.groupby(by="tree_thres").first() + + elif remove == "last": + gdf = gdf.groupby(by="tree_thres").last() + + return gdf + + +def get_random_point_in_polygon(poly): + """Generates random shapely Point geometry objects within a single + shapely Polygon object. + + Parameters + ---------- + poly : Shapely Polygon object + + Returns + ------- + p : Shapely Point object + """ + + (minx, miny, maxx, maxy) = poly.bounds + + while True: + p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy)) + + if poly.contains(p): + return p diff --git a/reference/Raster.qmd b/reference/Raster.qmd index 167b8cb..9fca366 100644 --- a/reference/Raster.qmd +++ b/reference/Raster.qmd @@ -1,613 +1,613 @@ -# Raster { #pyspatialml.Raster } - -`Raster(self, src, crs=None, transform=None, nodata=None, file_path=None, driver=None, tempdir=tempfile.tempdir, in_memory=False)` - -Creates a collection of file-based GDAL-supported raster -datasets that share a common coordinate reference system and -geometry. - -Raster objects encapsulate RasterLayer objects, which represent -single band raster datasets that can physically be represented by -either separate single-band raster files, multi-band raster files, -or any combination of individual bands from multi-band raster and -single-band raster datasets. - -## Attributes - -| Name | Type | Description | -|-------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| files | list | A list of the raster dataset files that are used in the Raster. This does not have to be the same length as the number of RasterLayers because some files may have multiple bands. | -| meta | dict | A dict containing the raster metadata. The dict contains the following keys/values: crs : the crs object transform : the Affine.affine transform object width : width of the Raster in pixels height : height of the Raster in pixels count : number of RasterLayers within the Raster dtype : the numpy datatype that represents lowest common denominator of the different dtypes for all of the layers in the Raster. | -| names | list | A list of the RasterLayer names. | -| block_shape | tuple | The default block_shape in (rows, cols) for reading windows of data in the Raster for out-of-memory processing. | - -## Methods - -| Name | Description | -| --- | --- | -| [aggregate](#pyspatialml.Raster.aggregate) | Aggregates a raster to (usually) a coarser grid cell size. | -| [alter](#pyspatialml.Raster.alter) | Apply a fitted scikit-learn transformer to a Raster object. | -| [append](#pyspatialml.Raster.append) | Method to add new RasterLayers to a Raster object. | -| [apply](#pyspatialml.Raster.apply) | Apply user-supplied function to a Raster object. | -| [block_shapes](#pyspatialml.Raster.block_shapes) | Generator for windows for optimal reading and writing based | -| [close](#pyspatialml.Raster.close) | Close all of the RasterLayer objects in the Raster. | -| [copy](#pyspatialml.Raster.copy) | Creates a shallow copy of a Raster object | -| [crop](#pyspatialml.Raster.crop) | Crops a Raster object by the supplied bounds. | -| [drop](#pyspatialml.Raster.drop) | Drop individual RasterLayers from a Raster object | -| [extract_raster](#pyspatialml.Raster.extract_raster) | Sample a Raster object by an aligned raster of labelled pixels. | -| [extract_vector](#pyspatialml.Raster.extract_vector) | Sample a Raster/RasterLayer using a geopandas GeoDataframe | -| [extract_xy](#pyspatialml.Raster.extract_xy) | Samples pixel values using an array of xy locations. | -| [head](#pyspatialml.Raster.head) | Return the first 10 rows from the Raster as a ndarray | -| [intersect](#pyspatialml.Raster.intersect) | Perform a intersect operation on the Raster object. | -| [mask](#pyspatialml.Raster.mask) | Mask a Raster object based on the outline of shapes in a | -| [predict](#pyspatialml.Raster.predict) | Apply prediction of a scikit learn model to a Raster. | -| [predict_proba](#pyspatialml.Raster.predict_proba) | Apply class probability prediction of a scikit learn model to a Raster. | -| [read](#pyspatialml.Raster.read) | Reads data from the Raster object into a numpy array. | -| [rename](#pyspatialml.Raster.rename) | Rename a RasterLayer within the Raster object. | -| [sample](#pyspatialml.Raster.sample) | Generates a random sample of according to size, and samples | -| [scale](#pyspatialml.Raster.scale) | Standardize (centre and scale) a Raster object by | -| [set_block_shape](#pyspatialml.Raster.set_block_shape) | Set the block shape of the raster, i.e. the height and width | -| [tail](#pyspatialml.Raster.tail) | Return the last 10 rows from the Raster as a ndarray | -| [to_crs](#pyspatialml.Raster.to_crs) | Reprojects a Raster object to a different crs. | -| [to_pandas](#pyspatialml.Raster.to_pandas) | Raster to pandas DataFrame. | -| [write](#pyspatialml.Raster.write) | Write the Raster object to a file. | - -### aggregate { #pyspatialml.Raster.aggregate } - -`Raster.aggregate(out_shape, resampling='nearest', file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Aggregates a raster to (usually) a coarser grid cell size. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| `out_shape` | tuple | New shape in (rows, cols). | _required_ | -| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | -| `file_path` | str (optional | File path to save to cropped raster. If not supplied then the aggregated raster is saved to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of the existing Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | -| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's dtype. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|-----------------------------------------------| -| pyspatialml.raster.Raster | Raster object aggregated to a new pixel size. | - -### alter { #pyspatialml.Raster.alter } - -`Raster.alter(transformer, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False)` - -Apply a fitted scikit-learn transformer to a Raster object. - -Can be used to transform a raster using methods such as StandardScaler, -RobustScaler etc. - -#### Parameters - -| Name | Type | Description | Default | -|---------------|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `transformer` | a sklearn.preprocessing.Transformer object | | _required_ | -| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | -| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | -| `progress` | bool (default False) | Show progress bar for operation. | `False` | - -#### Returns - -| Type | Description | -|--------------------------------------------------|---------------| -| Pyspatialml.Raster object with transformed data. | | - -### append { #pyspatialml.Raster.append } - -`Raster.append(other, in_place=False)` - -Method to add new RasterLayers to a Raster object. - -Note that this modifies the Raster object in-place by default. - -#### Parameters - -| Name | Type | Description | Default | -|------------|------------------------------------------|------------------------------------------------------------------------------------------------|------------| -| `other` | Raster object, or list of Raster objects | Object to append to the Raster. | _required_ | -| `in_place` | bool (default False) | Whether to change the Raster object in-place or leave original and return a new Raster object. | `False` | - -#### Returns - -| Type | Description | -|---------------------------|--------------------------------------| -| pyspatialml.raster.Raster | Returned only if `in_place` is False | - -### apply { #pyspatialml.Raster.apply } - -`Raster.apply(function, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False, function_args={}, **kwargs)` - -Apply user-supplied function to a Raster object. - -#### Parameters - -| Name | Type | Description | Default | -|-----------------|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `function` | function | Function that takes an numpy array as a single argument. | _required_ | -| `file_path` | str (optional | Optional path to save calculated Raster object. If not specified then a tempfile is used. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new Raster is created using the dtype of the calculation result. | `None)` | -| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels that represent nodata pixels. | `None)` | -| `progress` | bool (default False) | Optionally show progress of transform operations. | `False` | -| `function_args` | dict(optional) | Optionally pass arguments to the `function` as a dict or keyword arguments. | `{}` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|------------------------------------------| -| pyspatialml.raster.Raster | Raster containing the calculated result. | - -### block_shapes { #pyspatialml.Raster.block_shapes } - -`Raster.block_shapes(rows, cols)` - -Generator for windows for optimal reading and writing based -on the raster format Windows and returns as a tuple with xoff, -yoff, width, height. - -#### Parameters - -| Name | Type | Description | Default | -|--------|--------|-----------------------------|------------| -| `rows` | int | Height of window in rows. | _required_ | -| `cols` | int | Width of window in columns. | _required_ | - -### close { #pyspatialml.Raster.close } - -`Raster.close()` - -Close all of the RasterLayer objects in the Raster. - -Note that this will cause any rasters based on temporary files -to be removed. This is intended as a method of clearing -temporary files that may have accumulated during an analysis -session. - -### copy { #pyspatialml.Raster.copy } - -`Raster.copy(subset=None)` - -Creates a shallow copy of a Raster object - -Note that shallow in the context of a Raster object means that -an immutable copy of the object is made, however the on-disk and -in-memory file locations remain the same. - -#### Parameters - -| Name | Type | Description | Default | -|----------|--------|------------------------------------------------|-----------| -| `subset` | opt | A list of layer names to subset while copying. | `None` | - -#### Returns - -| Type | Description | -|---------------------------|---------------| -| pyspatialml.raster.Raster | | - -### crop { #pyspatialml.Raster.crop } - -`Raster.crop(bounds, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Crops a Raster object by the supplied bounds. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `bounds` | tuple | A tuple containing the bounding box to clip by in the form of (xmin, ymin, xmax, ymax). | _required_ | -| `file_path` | str (optional | File path to save to cropped raster. If not supplied then the cropped raster is saved to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff'). Default is 'GTiff' | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of theexisting Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | -| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|-------------------------------| -| pyspatialml.raster.Raster | Raster cropped to new extent. | - -### drop { #pyspatialml.Raster.drop } - -`Raster.drop(labels, in_place=False)` - -Drop individual RasterLayers from a Raster object - -Note that this modifies the Raster object in-place by default. - -#### Parameters - -| Name | Type | Description | Default | -|------------|---------------------------|-------------------------------------------------------------------------------------------------------|------------| -| `labels` | single label or list-like | Index (int) or layer name to drop. Can be a single integer or label, or a list of integers or labels. | _required_ | -| `in_place` | bool (default False) | Whether to change the Raster object in-place or leave original and return a new Raster object. | `False` | - -#### Returns - -| Type | Description | -|--------------------------------|-------------------------------------| -| pyspatialml.pyspatialml.Raster | Returned only if `in_place` is True | - -### extract_raster { #pyspatialml.Raster.extract_raster } - -`Raster.extract_raster(src, progress=False)` - -Sample a Raster object by an aligned raster of labelled pixels. - -#### Parameters - -| Name | Type | Description | Default | -|------------|-----------|-----------------------------------------------------------------------------------------|------------| -| `src` | | Single band raster containing labelled pixels as an open rasterio DatasetReader object. | _required_ | -| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | - -#### Returns - -| Type | Description | -|----------------------------------|----------------------------------------------------------------------------------| -| geopandas.geopandas.GeoDataFrame | Geodataframe containing extracted data as point features if `return_array=False` | - -### extract_vector { #pyspatialml.Raster.extract_vector } - -`Raster.extract_vector(gdf, progress=False)` - -Sample a Raster/RasterLayer using a geopandas GeoDataframe -containing points, lines or polygon features. - -#### Parameters - -| Name | Type | Description | Default | -|------------|-----------|-----------------------------------------------------------------------------------------------------------------------|------------| -| `gdf` | | Containing either point, line or polygon geometries. Overlapping geometries will cause the same pixels to be sampled. | _required_ | -| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | - -#### Returns - -| Type | Description | -|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| geopandas.geopandas.GeoDataframe | Containing extracted data as point geometries (one point per pixel). The resulting GeoDataFrame is indexed using a named pandas.MultiIndex, with `pixel_idx` index referring to the index of each pixel that was sampled, and the `geometry_idx` index referring to the index of the each geometry in the supplied `gdf`. This makes it possible to keep track of how sampled pixel relates to the original geometries, i.e. multiple pixels being extracted within the area of a single polygon that can be referred to using the `geometry_idx`. The extracted data can subsequently be joined with the attribute table of the supplied `gdf` using: training_py = geopandas.read_file(nc.polygons) df = self.stack.extract_vector(gdf=training_py) df = df.dropna() df = df.merge( right=training_py.loc[:, ("id", "label")], left_on="polygon_idx", right_on="id", right_index=True ) | - -### extract_xy { #pyspatialml.Raster.extract_xy } - -`Raster.extract_xy(xys, return_array=False, progress=False)` - -Samples pixel values using an array of xy locations. - -#### Parameters - -| Name | Type | Description | Default | -|----------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `xys` | 2d array-like | x and y coordinates from which to sample the raster (n_samples, xys). | _required_ | -| `return_array` | bool(opt) | By default the extracted pixel values are returned as a geopandas.GeoDataFrame. If `return_array=True` then the extracted pixel values are returned as a tuple of numpy.ndarrays. | `False` | -| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | - -#### Returns - -| Type | Description | -|----------------------------------|----------------------------------------------------------------------------------------| -| geopandas.geopandas.GeoDataframe | Containing extracted data as point geometries if `return_array=False`. | -| numpy.numpy.ndarray | 2d masked array containing sampled raster values (sample, bands) at the x,y locations. | - -### head { #pyspatialml.Raster.head } - -`Raster.head()` - -Return the first 10 rows from the Raster as a ndarray - -### intersect { #pyspatialml.Raster.intersect } - -`Raster.intersect(file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Perform a intersect operation on the Raster object. - -Computes the geometric intersection of the RasterLayers with -the Raster object. This will cause nodata values in any of -the rasters to be propagated through all of the output rasters. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `file_path` | str (optional | File path to save to resulting Raster. If not supplied then the resulting Raster is saved to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of the existing Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | -| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels that represent nodata to the new value. | `None)` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|------------------------------------------------------------------------------------------------| -| pyspatialml.raster.Raster | Raster with layers that are masked based on a union of all masks in the suite of RasterLayers. | - -### mask { #pyspatialml.Raster.mask } - -`Raster.mask(shapes, invert=False, crop=True, pad=False, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Mask a Raster object based on the outline of shapes in a -geopandas.GeoDataFrame - -#### Parameters - -| Name | Type | Description | Default | -|-------------|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `shapes` | geopandas.geopandas.GeoDataFrame | GeoDataFrame containing masking features. | _required_ | -| `invert` | bool (default False) | If False then pixels outside shapes will be masked. If True then pixels inside shape will be masked. | `False` | -| `crop` | bool (default True) | Crop the raster to the extent of the shapes. | `True` | -| `pad` | bool (default False) | If True, the features will be padded in each direction by one half of a pixel prior to cropping raster. | `False` | -| `file_path` | str (optional | File path to save to resulting Raster. If not supplied then the resulting Raster is saved to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the cropped Raster is created using the existing dtype, which usesa dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | -| `nodata` | any number (optional | Nodata value for cropped dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels to the new nodata value, and changes the metadata of the raster. | `None)` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|--------------------------------|----------------------------| -| pyspatialml.pyspatialml.Raster | Raster with masked layers. | - -### predict { #pyspatialml.Raster.predict } - -`Raster.predict(estimator, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False, constants=None, **kwargs)` - -Apply prediction of a scikit learn model to a Raster. - -The model can represent any scikit learn model or compatible -api with a `fit` and `predict` method. These can consist of -classification or regression models. Multi-class -classifications and multi-target regressions are also -supported. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `estimator` | estimator object implementing 'fit' | The object to use to fit the data. | _required_ | -| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export | `'GTiff'` | -| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, np.float32 is assumed. | `None)` | -| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | -| `progress` | bool (default False) | Show progress bar for prediction. | `False` | -| `constants` | | Constant features to add to the Raster object with each value in a list or 1d ndarray representing an additional feature. If a list-like object of values os passed, then each numeric value will be appended as constant features to the last columns in the data. It is therefore important that all features including constant features are present in the same order as what was used to train the model. If a dict is passed, then the keys of the dict must refer to the names of raster layers in the Raster object. In this case, the values of the dict will replace the values of the raster layers in the Raster object. | `None` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| pyspatialml.raster.Raster | Raster object containing prediction results as a RasterLayers. For classification and regression models, the Raster will contain a single RasterLayer, unless the model is multi-class or multi-target. Layers are named automatically as `pred_raw_n` with n = 1, 2, 3 ..n. | - -### predict_proba { #pyspatialml.Raster.predict_proba } - -`Raster.predict_proba(estimator, file_path=None, in_memory=False, indexes=None, driver='GTiff', dtype=None, nodata=None, constants=None, progress=False, **kwargs)` - -Apply class probability prediction of a scikit learn model to a Raster. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `estimator` | estimator object implementing 'fit' | The object to use to fit the data. | _required_ | -| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `indexes` | list of integers (optional | List of class indices to export. In some circumstances, only a subset of the class probability estimations are desired, for instance when performing a binary classification only the probabilities for the positive class may be desired. | `None)` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | -| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | -| `progress` | bool (default False) | Show progress bar for prediction. | `False` | -| `constants` | | Constant features to add to the Raster object with each value in a list or 1d ndarray representing an additional feature. If a list-like object of values os passed, then each numeric value will be appended as constant features to the last columns in the data. It is therefore important that all features including constant features are present in the same order as what was used to train the model. If a dict is passed, then the keys of the dict must refer to the names of raster layers in the Raster object. In this case, the values of the dict will replace the values of the raster layers in the Raster object. | `None` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| pyspatialml.raster.Raster | Raster containing predicted class probabilities. Each predicted class is represented by a RasterLayer object. The RasterLayers are named `prob_n` for 1,2,3..n, with `n` based on the index position of the classes, not the number of the class itself. For example, a classification model predicting classes with integer values of 1, 3, and 5 would result in three RasterLayers named 'prob_1', 'prob_2' and 'prob_3'. | - -### read { #pyspatialml.Raster.read } - -`Raster.read(masked=False, window=None, out_shape=None, resampling='nearest', as_df=False, **kwargs)` - -Reads data from the Raster object into a numpy array. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| `masked` | bool (default False) | Read data into a masked array. | `False` | -| `window` | rasterio.window.Window object (optional | Tuple of col_off, row_off, width, height of a window of data to read a chunk of data into a ndarray. | `None)` | -| `out_shape` | tuple (optional | Shape of shape of array (rows, cols) to read data into using decimated reads. | `None)` | -| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | -| `as_df` | bool (default False) | Whether to return the data as a pandas.DataFrame with columns named by the RasterLayer names. | `False` | -| `**kwargs` | dict | Other arguments to pass to rasterio.DatasetReader.read method | `{}` | - -#### Returns - -| Type | Description | -|---------|---------------------------------------------------------------------------------------| -| ndarray | Raster values in 3d ndarray with the dimensions in order of (band, row, and column). | - -### rename { #pyspatialml.Raster.rename } - -`Raster.rename(names, in_place=False)` - -Rename a RasterLayer within the Raster object. - -#### Parameters - -| Name | Type | Description | Default | -|------------|----------------------|---------------------------------------------------------------------------------------------------------|------------| -| `names` | dict | dict of old_name : new_name | _required_ | -| `in_place` | bool (default False) | Whether to change names of the Raster object in-place or leave original and return a new Raster object. | `False` | - -#### Returns - -| Type | Description | -|--------------------------------|--------------------------------------| -| pyspatialml.pyspatialml.Raster | Returned only if `in_place` is False | - -### sample { #pyspatialml.Raster.sample } - -`Raster.sample(size, strata=None, return_array=False, random_state=None)` - -Generates a random sample of according to size, and samples -the pixel values. - -#### Parameters - -| Name | Type | Description | Default | -|----------------|---------------------------------|-----------------------------------------------------------------------------------------------------------------------|------------| -| `size` | int | Number of random samples or number of samples per strata if a `strata` object is supplied. | _required_ | -| `strata` | pyspatialml Raster object (opt) | Whether to use stratified instead of random sampling. Strata can be supplied using another pyspatialml.Raster object. | `None` | -| `return_array` | bool(opt) | Optionally return extracted data as separate X and xy masked numpy arrays. | `False` | -| `random_state` | int(opt) | integer to use within random.seed. | `None` | - -#### Returns - -| Type | Description | -|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| pandas.pandas.DataFrame | DataFrame containing values of names of RasterLayers in the Raster if `return_array` is False. | -| tuple | A tuple containing two elements if `return_array` is True: - numpy.ndarray Numpy array of extracted raster values, typically 2d. - numpy.ndarray 2D numpy array of xy coordinates of extracted values. | - -### scale { #pyspatialml.Raster.scale } - -`Raster.scale(centre=True, scale=True, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False)` - -Standardize (centre and scale) a Raster object by -subtracting the mean and dividing by the standard deviation for -each layer in the object. - -The mean and standard deviation statistics are calculated -for each layer separately. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `centre` | bool | Whether to subtract the mean from each layer. | `is True` | -| `scale` | bool | Whether to divide each layer by the standard deviation of the layer. | `is True` | -| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | -| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | -| `progress` | bool (default False) | Show progress bar for operation. | `False` | - -#### Returns - -| Type | Description | -|-----------------------------------------------|---------------| -| Pyspatialml.Raster object with rescaled data. | | - -### set_block_shape { #pyspatialml.Raster.set_block_shape } - -`Raster.set_block_shape(value)` - -Set the block shape of the raster, i.e. the height and width -of windows to read in chunks for the predict, predict_proba, -apply, and other supported-methods. - -Note block shape can also be set with `myraster.block_shape = (500, 500)` - -#### Parameters - -| Name | Type | Description | Default | -|---------|--------|-------------------------------------------------|------------| -| `value` | tuple | A tuple of (height, width) for the block window | _required_ | - -### tail { #pyspatialml.Raster.tail } - -`Raster.tail()` - -Return the last 10 rows from the Raster as a ndarray - -### to_crs { #pyspatialml.Raster.to_crs } - -`Raster.to_crs(crs, resampling='nearest', file_path=None, in_memory=False, driver='GTiff', nodata=None, n_jobs=1, warp_mem_lim=0, progress=False, **kwargs)` - -Reprojects a Raster object to a different crs. - -#### Parameters - -| Name | Type | Description | Default | -|----------------|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| `crs` | rasterio.transform.CRS object, or dict | Example: CRS({'init': 'EPSG:4326'}) | _required_ | -| `resampling` | str (default 'nearest') | Resampling method to use. One of the following: nearest, bilinear, cubic, cubic_spline, lanczos, average, mode, max (GDAL >= 2.2), min (GDAL >= 2.2), med (GDAL >= 2.2), q1 (GDAL >= 2.2), q3 (GDAL >= 2.2) | `'nearest'` | -| `file_path` | str (optional | Optional path to save reprojected Raster object. If not specified then a tempfile is used. | `None)` | -| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | -| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | -| `nodata` | any number (optional | Nodata value for new dataset. If not specified then the existing nodata value of the Raster object is used, which can accommodate the dtypes of the individual layers in the Raster. | `None)` | -| `n_jobs` | int (default 1) | The number of warp worker threads. | `1` | -| `warp_mem_lim` | int (default 0) | The warp operation memory limit in MB. Larger values allow the warp operation to be carried out in fewer chunks. The amount of memory required to warp a 3-band uint8 2000 row x 2000 col raster to a destination of the same size is approximately 56 MB. The default (0) means 64 MB with GDAL 2.2. | `0` | -| `progress` | bool (default False) | Optionally show progress of transform operations. | `False` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|--------------------------------| -| pyspatialml.raster.Raster | Raster following reprojection. | - -### to_pandas { #pyspatialml.Raster.to_pandas } - -`Raster.to_pandas(max_pixels=None, resampling='nearest')` - -Raster to pandas DataFrame. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| `max_pixels` | | Maximum number of pixels to sample. By default all pixels are used. | `None` | -| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | - -#### Returns - -| Type | Description | -|-------------------------|----------------------------------------------------------------------------------------------------------| -| pandas.pandas.DataFrame | DataFrame containing values of names of RasterLayers in the Raster as columns, and pixel values as rows. | - -### write { #pyspatialml.Raster.write } - -`Raster.write(file_path, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Write the Raster object to a file. - -Overrides the write RasterBase class method, which is a partial -function of the rasterio.DatasetReader.write method. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| -| `file_path` | str | File path used to save the Raster object. | _required_ | -| `driver` | str (default is 'GTiff'). | Name of GDAL driver used to save Raster data. | `'GTiff'` | -| `dtype` | str (opt | Optionally specify a numpy compatible data type when saving to file. If not specified, a data type is selected based on the data types of RasterLayers in the Raster object. | `None)` | -| `nodata` | any number (opt | Optionally assign a new nodata value when saving to file. If not specified a nodata value based on the minimum permissible value for the data types of RasterLayers in the Raster object is used. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|---------------------------|------------------------------------| +# Raster { #pyspatialml.Raster } + +`Raster(self, src, crs=None, transform=None, nodata=None, file_path=None, driver=None, tempdir=tempfile.tempdir, in_memory=False)` + +Creates a collection of file-based GDAL-supported raster +datasets that share a common coordinate reference system and +geometry. + +Raster objects encapsulate RasterLayer objects, which represent +single band raster datasets that can physically be represented by +either separate single-band raster files, multi-band raster files, +or any combination of individual bands from multi-band raster and +single-band raster datasets. + +## Attributes + +| Name | Type | Description | +|-------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| files | list | A list of the raster dataset files that are used in the Raster. This does not have to be the same length as the number of RasterLayers because some files may have multiple bands. | +| meta | dict | A dict containing the raster metadata. The dict contains the following keys/values: crs : the crs object transform : the Affine.affine transform object width : width of the Raster in pixels height : height of the Raster in pixels count : number of RasterLayers within the Raster dtype : the numpy datatype that represents lowest common denominator of the different dtypes for all of the layers in the Raster. | +| names | list | A list of the RasterLayer names. | +| block_shape | tuple | The default block_shape in (rows, cols) for reading windows of data in the Raster for out-of-memory processing. | + +## Methods + +| Name | Description | +| --- | --- | +| [aggregate](#pyspatialml.Raster.aggregate) | Aggregates a raster to (usually) a coarser grid cell size. | +| [alter](#pyspatialml.Raster.alter) | Apply a fitted scikit-learn transformer to a Raster object. | +| [append](#pyspatialml.Raster.append) | Method to add new RasterLayers to a Raster object. | +| [apply](#pyspatialml.Raster.apply) | Apply user-supplied function to a Raster object. | +| [block_shapes](#pyspatialml.Raster.block_shapes) | Generator for windows for optimal reading and writing based | +| [close](#pyspatialml.Raster.close) | Close all of the RasterLayer objects in the Raster. | +| [copy](#pyspatialml.Raster.copy) | Creates a shallow copy of a Raster object | +| [crop](#pyspatialml.Raster.crop) | Crops a Raster object by the supplied bounds. | +| [drop](#pyspatialml.Raster.drop) | Drop individual RasterLayers from a Raster object | +| [extract_raster](#pyspatialml.Raster.extract_raster) | Sample a Raster object by an aligned raster of labelled pixels. | +| [extract_vector](#pyspatialml.Raster.extract_vector) | Sample a Raster/RasterLayer using a geopandas GeoDataframe | +| [extract_xy](#pyspatialml.Raster.extract_xy) | Samples pixel values using an array of xy locations. | +| [head](#pyspatialml.Raster.head) | Return the first 10 rows from the Raster as a ndarray | +| [intersect](#pyspatialml.Raster.intersect) | Perform a intersect operation on the Raster object. | +| [mask](#pyspatialml.Raster.mask) | Mask a Raster object based on the outline of shapes in a | +| [predict](#pyspatialml.Raster.predict) | Apply prediction of a scikit learn model to a Raster. | +| [predict_proba](#pyspatialml.Raster.predict_proba) | Apply class probability prediction of a scikit learn model to a Raster. | +| [read](#pyspatialml.Raster.read) | Reads data from the Raster object into a numpy array. | +| [rename](#pyspatialml.Raster.rename) | Rename a RasterLayer within the Raster object. | +| [sample](#pyspatialml.Raster.sample) | Generates a random sample of according to size, and samples | +| [scale](#pyspatialml.Raster.scale) | Standardize (centre and scale) a Raster object by | +| [set_block_shape](#pyspatialml.Raster.set_block_shape) | Set the block shape of the raster, i.e. the height and width | +| [tail](#pyspatialml.Raster.tail) | Return the last 10 rows from the Raster as a ndarray | +| [to_crs](#pyspatialml.Raster.to_crs) | Reprojects a Raster object to a different crs. | +| [to_pandas](#pyspatialml.Raster.to_pandas) | Raster to pandas DataFrame. | +| [write](#pyspatialml.Raster.write) | Write the Raster object to a file. | + +### aggregate { #pyspatialml.Raster.aggregate } + +`Raster.aggregate(out_shape, resampling='nearest', file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Aggregates a raster to (usually) a coarser grid cell size. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| `out_shape` | tuple | New shape in (rows, cols). | _required_ | +| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | +| `file_path` | str (optional | File path to save to cropped raster. If not supplied then the aggregated raster is saved to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of the existing Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | +| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's dtype. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|-----------------------------------------------| +| pyspatialml.raster.Raster | Raster object aggregated to a new pixel size. | + +### alter { #pyspatialml.Raster.alter } + +`Raster.alter(transformer, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False)` + +Apply a fitted scikit-learn transformer to a Raster object. + +Can be used to transform a raster using methods such as StandardScaler, +RobustScaler etc. + +#### Parameters + +| Name | Type | Description | Default | +|---------------|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `transformer` | a sklearn.preprocessing.Transformer object | | _required_ | +| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | +| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | +| `progress` | bool (default False) | Show progress bar for operation. | `False` | + +#### Returns + +| Type | Description | +|--------------------------------------------------|---------------| +| Pyspatialml.Raster object with transformed data. | | + +### append { #pyspatialml.Raster.append } + +`Raster.append(other, in_place=False)` + +Method to add new RasterLayers to a Raster object. + +Note that this modifies the Raster object in-place by default. + +#### Parameters + +| Name | Type | Description | Default | +|------------|------------------------------------------|------------------------------------------------------------------------------------------------|------------| +| `other` | Raster object, or list of Raster objects | Object to append to the Raster. | _required_ | +| `in_place` | bool (default False) | Whether to change the Raster object in-place or leave original and return a new Raster object. | `False` | + +#### Returns + +| Type | Description | +|---------------------------|--------------------------------------| +| pyspatialml.raster.Raster | Returned only if `in_place` is False | + +### apply { #pyspatialml.Raster.apply } + +`Raster.apply(function, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False, function_args={}, **kwargs)` + +Apply user-supplied function to a Raster object. + +#### Parameters + +| Name | Type | Description | Default | +|-----------------|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `function` | function | Function that takes an numpy array as a single argument. | _required_ | +| `file_path` | str (optional | Optional path to save calculated Raster object. If not specified then a tempfile is used. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new Raster is created using the dtype of the calculation result. | `None)` | +| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels that represent nodata pixels. | `None)` | +| `progress` | bool (default False) | Optionally show progress of transform operations. | `False` | +| `function_args` | dict(optional) | Optionally pass arguments to the `function` as a dict or keyword arguments. | `{}` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|------------------------------------------| +| pyspatialml.raster.Raster | Raster containing the calculated result. | + +### block_shapes { #pyspatialml.Raster.block_shapes } + +`Raster.block_shapes(rows, cols)` + +Generator for windows for optimal reading and writing based +on the raster format Windows and returns as a tuple with xoff, +yoff, width, height. + +#### Parameters + +| Name | Type | Description | Default | +|--------|--------|-----------------------------|------------| +| `rows` | int | Height of window in rows. | _required_ | +| `cols` | int | Width of window in columns. | _required_ | + +### close { #pyspatialml.Raster.close } + +`Raster.close()` + +Close all of the RasterLayer objects in the Raster. + +Note that this will cause any rasters based on temporary files +to be removed. This is intended as a method of clearing +temporary files that may have accumulated during an analysis +session. + +### copy { #pyspatialml.Raster.copy } + +`Raster.copy(subset=None)` + +Creates a shallow copy of a Raster object + +Note that shallow in the context of a Raster object means that +an immutable copy of the object is made, however the on-disk and +in-memory file locations remain the same. + +#### Parameters + +| Name | Type | Description | Default | +|----------|--------|------------------------------------------------|-----------| +| `subset` | opt | A list of layer names to subset while copying. | `None` | + +#### Returns + +| Type | Description | +|---------------------------|---------------| +| pyspatialml.raster.Raster | | + +### crop { #pyspatialml.Raster.crop } + +`Raster.crop(bounds, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Crops a Raster object by the supplied bounds. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `bounds` | tuple | A tuple containing the bounding box to clip by in the form of (xmin, ymin, xmax, ymax). | _required_ | +| `file_path` | str (optional | File path to save to cropped raster. If not supplied then the cropped raster is saved to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff'). Default is 'GTiff' | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of theexisting Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | +| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|-------------------------------| +| pyspatialml.raster.Raster | Raster cropped to new extent. | + +### drop { #pyspatialml.Raster.drop } + +`Raster.drop(labels, in_place=False)` + +Drop individual RasterLayers from a Raster object + +Note that this modifies the Raster object in-place by default. + +#### Parameters + +| Name | Type | Description | Default | +|------------|---------------------------|-------------------------------------------------------------------------------------------------------|------------| +| `labels` | single label or list-like | Index (int) or layer name to drop. Can be a single integer or label, or a list of integers or labels. | _required_ | +| `in_place` | bool (default False) | Whether to change the Raster object in-place or leave original and return a new Raster object. | `False` | + +#### Returns + +| Type | Description | +|--------------------------------|-------------------------------------| +| pyspatialml.pyspatialml.Raster | Returned only if `in_place` is True | + +### extract_raster { #pyspatialml.Raster.extract_raster } + +`Raster.extract_raster(src, progress=False)` + +Sample a Raster object by an aligned raster of labelled pixels. + +#### Parameters + +| Name | Type | Description | Default | +|------------|-----------|-----------------------------------------------------------------------------------------|------------| +| `src` | | Single band raster containing labelled pixels as an open rasterio DatasetReader object. | _required_ | +| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | + +#### Returns + +| Type | Description | +|----------------------------------|----------------------------------------------------------------------------------| +| geopandas.geopandas.GeoDataFrame | Geodataframe containing extracted data as point features if `return_array=False` | + +### extract_vector { #pyspatialml.Raster.extract_vector } + +`Raster.extract_vector(gdf, progress=False)` + +Sample a Raster/RasterLayer using a geopandas GeoDataframe +containing points, lines or polygon features. + +#### Parameters + +| Name | Type | Description | Default | +|------------|-----------|-----------------------------------------------------------------------------------------------------------------------|------------| +| `gdf` | | Containing either point, line or polygon geometries. Overlapping geometries will cause the same pixels to be sampled. | _required_ | +| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | + +#### Returns + +| Type | Description | +|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| geopandas.geopandas.GeoDataframe | Containing extracted data as point geometries (one point per pixel). The resulting GeoDataFrame is indexed using a named pandas.MultiIndex, with `pixel_idx` index referring to the index of each pixel that was sampled, and the `geometry_idx` index referring to the index of the each geometry in the supplied `gdf`. This makes it possible to keep track of how sampled pixel relates to the original geometries, i.e. multiple pixels being extracted within the area of a single polygon that can be referred to using the `geometry_idx`. The extracted data can subsequently be joined with the attribute table of the supplied `gdf` using: training_py = geopandas.read_file(nc.polygons) df = self.stack.extract_vector(gdf=training_py) df = df.dropna() df = df.merge( right=training_py.loc[:, ("id", "label")], left_on="polygon_idx", right_on="id", right_index=True ) | + +### extract_xy { #pyspatialml.Raster.extract_xy } + +`Raster.extract_xy(xys, return_array=False, progress=False)` + +Samples pixel values using an array of xy locations. + +#### Parameters + +| Name | Type | Description | Default | +|----------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `xys` | 2d array-like | x and y coordinates from which to sample the raster (n_samples, xys). | _required_ | +| `return_array` | bool(opt) | By default the extracted pixel values are returned as a geopandas.GeoDataFrame. If `return_array=True` then the extracted pixel values are returned as a tuple of numpy.ndarrays. | `False` | +| `progress` | bool(opt) | Show a progress bar for extraction. | `False` | + +#### Returns + +| Type | Description | +|----------------------------------|----------------------------------------------------------------------------------------| +| geopandas.geopandas.GeoDataframe | Containing extracted data as point geometries if `return_array=False`. | +| numpy.numpy.ndarray | 2d masked array containing sampled raster values (sample, bands) at the x,y locations. | + +### head { #pyspatialml.Raster.head } + +`Raster.head()` + +Return the first 10 rows from the Raster as a ndarray + +### intersect { #pyspatialml.Raster.intersect } + +`Raster.intersect(file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Perform a intersect operation on the Raster object. + +Computes the geometric intersection of the RasterLayers with +the Raster object. This will cause nodata values in any of +the rasters to be propagated through all of the output rasters. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `file_path` | str (optional | File path to save to resulting Raster. If not supplied then the resulting Raster is saved to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the new intersected Raster is created using the dtype of the existing Raster dataset, which uses a dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | +| `nodata` | any number (optional | Nodata value for new dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels that represent nodata to the new value. | `None)` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|------------------------------------------------------------------------------------------------| +| pyspatialml.raster.Raster | Raster with layers that are masked based on a union of all masks in the suite of RasterLayers. | + +### mask { #pyspatialml.Raster.mask } + +`Raster.mask(shapes, invert=False, crop=True, pad=False, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Mask a Raster object based on the outline of shapes in a +geopandas.GeoDataFrame + +#### Parameters + +| Name | Type | Description | Default | +|-------------|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `shapes` | geopandas.geopandas.GeoDataFrame | GeoDataFrame containing masking features. | _required_ | +| `invert` | bool (default False) | If False then pixels outside shapes will be masked. If True then pixels inside shape will be masked. | `False` | +| `crop` | bool (default True) | Crop the raster to the extent of the shapes. | `True` | +| `pad` | bool (default False) | If True, the features will be padded in each direction by one half of a pixel prior to cropping raster. | `False` | +| `file_path` | str (optional | File path to save to resulting Raster. If not supplied then the resulting Raster is saved to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Coerce RasterLayers to the specified dtype. If not specified then the cropped Raster is created using the existing dtype, which usesa dtype that can accommodate the data types of all of the individual RasterLayers. | `None)` | +| `nodata` | any number (optional | Nodata value for cropped dataset. If not specified then a nodata value is set based on the minimum permissible value of the Raster's data type. Note that this changes the values of the pixels to the new nodata value, and changes the metadata of the raster. | `None)` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|--------------------------------|----------------------------| +| pyspatialml.pyspatialml.Raster | Raster with masked layers. | + +### predict { #pyspatialml.Raster.predict } + +`Raster.predict(estimator, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False, constants=None, **kwargs)` + +Apply prediction of a scikit learn model to a Raster. + +The model can represent any scikit learn model or compatible +api with a `fit` and `predict` method. These can consist of +classification or regression models. Multi-class +classifications and multi-target regressions are also +supported. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `estimator` | estimator object implementing 'fit' | The object to use to fit the data. | _required_ | +| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export | `'GTiff'` | +| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, np.float32 is assumed. | `None)` | +| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | +| `progress` | bool (default False) | Show progress bar for prediction. | `False` | +| `constants` | | Constant features to add to the Raster object with each value in a list or 1d ndarray representing an additional feature. If a list-like object of values os passed, then each numeric value will be appended as constant features to the last columns in the data. It is therefore important that all features including constant features are present in the same order as what was used to train the model. If a dict is passed, then the keys of the dict must refer to the names of raster layers in the Raster object. In this case, the values of the dict will replace the values of the raster layers in the Raster object. | `None` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| pyspatialml.raster.Raster | Raster object containing prediction results as a RasterLayers. For classification and regression models, the Raster will contain a single RasterLayer, unless the model is multi-class or multi-target. Layers are named automatically as `pred_raw_n` with n = 1, 2, 3 ..n. | + +### predict_proba { #pyspatialml.Raster.predict_proba } + +`Raster.predict_proba(estimator, file_path=None, in_memory=False, indexes=None, driver='GTiff', dtype=None, nodata=None, constants=None, progress=False, **kwargs)` + +Apply class probability prediction of a scikit learn model to a Raster. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `estimator` | estimator object implementing 'fit' | The object to use to fit the data. | _required_ | +| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `indexes` | list of integers (optional | List of class indices to export. In some circumstances, only a subset of the class probability estimations are desired, for instance when performing a binary classification only the probabilities for the positive class may be desired. | `None)` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | +| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | +| `progress` | bool (default False) | Show progress bar for prediction. | `False` | +| `constants` | | Constant features to add to the Raster object with each value in a list or 1d ndarray representing an additional feature. If a list-like object of values os passed, then each numeric value will be appended as constant features to the last columns in the data. It is therefore important that all features including constant features are present in the same order as what was used to train the model. If a dict is passed, then the keys of the dict must refer to the names of raster layers in the Raster object. In this case, the values of the dict will replace the values of the raster layers in the Raster object. | `None` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| pyspatialml.raster.Raster | Raster containing predicted class probabilities. Each predicted class is represented by a RasterLayer object. The RasterLayers are named `prob_n` for 1,2,3..n, with `n` based on the index position of the classes, not the number of the class itself. For example, a classification model predicting classes with integer values of 1, 3, and 5 would result in three RasterLayers named 'prob_1', 'prob_2' and 'prob_3'. | + +### read { #pyspatialml.Raster.read } + +`Raster.read(masked=False, window=None, out_shape=None, resampling='nearest', as_df=False, **kwargs)` + +Reads data from the Raster object into a numpy array. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| `masked` | bool (default False) | Read data into a masked array. | `False` | +| `window` | rasterio.window.Window object (optional | Tuple of col_off, row_off, width, height of a window of data to read a chunk of data into a ndarray. | `None)` | +| `out_shape` | tuple (optional | Shape of shape of array (rows, cols) to read data into using decimated reads. | `None)` | +| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | +| `as_df` | bool (default False) | Whether to return the data as a pandas.DataFrame with columns named by the RasterLayer names. | `False` | +| `**kwargs` | dict | Other arguments to pass to rasterio.DatasetReader.read method | `{}` | + +#### Returns + +| Type | Description | +|---------|---------------------------------------------------------------------------------------| +| ndarray | Raster values in 3d ndarray with the dimensions in order of (band, row, and column). | + +### rename { #pyspatialml.Raster.rename } + +`Raster.rename(names, in_place=False)` + +Rename a RasterLayer within the Raster object. + +#### Parameters + +| Name | Type | Description | Default | +|------------|----------------------|---------------------------------------------------------------------------------------------------------|------------| +| `names` | dict | dict of old_name : new_name | _required_ | +| `in_place` | bool (default False) | Whether to change names of the Raster object in-place or leave original and return a new Raster object. | `False` | + +#### Returns + +| Type | Description | +|--------------------------------|--------------------------------------| +| pyspatialml.pyspatialml.Raster | Returned only if `in_place` is False | + +### sample { #pyspatialml.Raster.sample } + +`Raster.sample(size, strata=None, return_array=False, random_state=None)` + +Generates a random sample of according to size, and samples +the pixel values. + +#### Parameters + +| Name | Type | Description | Default | +|----------------|---------------------------------|-----------------------------------------------------------------------------------------------------------------------|------------| +| `size` | int | Number of random samples or number of samples per strata if a `strata` object is supplied. | _required_ | +| `strata` | pyspatialml Raster object (opt) | Whether to use stratified instead of random sampling. Strata can be supplied using another pyspatialml.Raster object. | `None` | +| `return_array` | bool(opt) | Optionally return extracted data as separate X and xy masked numpy arrays. | `False` | +| `random_state` | int(opt) | integer to use within random.seed. | `None` | + +#### Returns + +| Type | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| pandas.pandas.DataFrame | DataFrame containing values of names of RasterLayers in the Raster if `return_array` is False. | +| tuple | A tuple containing two elements if `return_array` is True: - numpy.ndarray Numpy array of extracted raster values, typically 2d. - numpy.ndarray 2D numpy array of xy coordinates of extracted values. | + +### scale { #pyspatialml.Raster.scale } + +`Raster.scale(centre=True, scale=True, file_path=None, in_memory=False, driver='GTiff', dtype=None, nodata=None, progress=False)` + +Standardize (centre and scale) a Raster object by +subtracting the mean and dividing by the standard deviation for +each layer in the object. + +The mean and standard deviation statistics are calculated +for each layer separately. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `centre` | bool | Whether to subtract the mean from each layer. | `is True` | +| `scale` | bool | Whether to divide each layer by the standard deviation of the layer. | `is True` | +| `file_path` | str (optional | Path to a GeoTiff raster for the prediction results. If not specified then the output is written to a temporary file. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `dtype` | str (optional | Optionally specify a GDAL compatible data type when saving to file. If not specified, a data type is set based on the data type of the prediction. | `None)` | +| `nodata` | any number (optional | Nodata value for file export. If not specified then the nodata value is derived from the minimum permissible value for the given data type. | `None)` | +| `progress` | bool (default False) | Show progress bar for operation. | `False` | + +#### Returns + +| Type | Description | +|-----------------------------------------------|---------------| +| Pyspatialml.Raster object with rescaled data. | | + +### set_block_shape { #pyspatialml.Raster.set_block_shape } + +`Raster.set_block_shape(value)` + +Set the block shape of the raster, i.e. the height and width +of windows to read in chunks for the predict, predict_proba, +apply, and other supported-methods. + +Note block shape can also be set with `myraster.block_shape = (500, 500)` + +#### Parameters + +| Name | Type | Description | Default | +|---------|--------|-------------------------------------------------|------------| +| `value` | tuple | A tuple of (height, width) for the block window | _required_ | + +### tail { #pyspatialml.Raster.tail } + +`Raster.tail()` + +Return the last 10 rows from the Raster as a ndarray + +### to_crs { #pyspatialml.Raster.to_crs } + +`Raster.to_crs(crs, resampling='nearest', file_path=None, in_memory=False, driver='GTiff', nodata=None, n_jobs=1, warp_mem_lim=0, progress=False, **kwargs)` + +Reprojects a Raster object to a different crs. + +#### Parameters + +| Name | Type | Description | Default | +|----------------|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| `crs` | rasterio.transform.CRS object, or dict | Example: CRS({'init': 'EPSG:4326'}) | _required_ | +| `resampling` | str (default 'nearest') | Resampling method to use. One of the following: nearest, bilinear, cubic, cubic_spline, lanczos, average, mode, max (GDAL >= 2.2), min (GDAL >= 2.2), med (GDAL >= 2.2), q1 (GDAL >= 2.2), q3 (GDAL >= 2.2) | `'nearest'` | +| `file_path` | str (optional | Optional path to save reprojected Raster object. If not specified then a tempfile is used. | `None)` | +| `in_memory` | bool | Whether to initiated the Raster from an array and store the data in-memory using Rasterio's in-memory files. | `is False` | +| `driver` | str (default 'GTiff') | Named of GDAL-supported driver for file export. | `'GTiff'` | +| `nodata` | any number (optional | Nodata value for new dataset. If not specified then the existing nodata value of the Raster object is used, which can accommodate the dtypes of the individual layers in the Raster. | `None)` | +| `n_jobs` | int (default 1) | The number of warp worker threads. | `1` | +| `warp_mem_lim` | int (default 0) | The warp operation memory limit in MB. Larger values allow the warp operation to be carried out in fewer chunks. The amount of memory required to warp a 3-band uint8 2000 row x 2000 col raster to a destination of the same size is approximately 56 MB. The default (0) means 64 MB with GDAL 2.2. | `0` | +| `progress` | bool (default False) | Optionally show progress of transform operations. | `False` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|--------------------------------| +| pyspatialml.raster.Raster | Raster following reprojection. | + +### to_pandas { #pyspatialml.Raster.to_pandas } + +`Raster.to_pandas(max_pixels=None, resampling='nearest')` + +Raster to pandas DataFrame. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| `max_pixels` | | Maximum number of pixels to sample. By default all pixels are used. | `None` | +| `resampling` | str (default 'nearest') | Resampling method to use when applying decimated reads when out_shape is specified. Supported methods are: 'average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'q1', 'q3'. | `'nearest'` | + +#### Returns + +| Type | Description | +|-------------------------|----------------------------------------------------------------------------------------------------------| +| pandas.pandas.DataFrame | DataFrame containing values of names of RasterLayers in the Raster as columns, and pixel values as rows. | + +### write { #pyspatialml.Raster.write } + +`Raster.write(file_path, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Write the Raster object to a file. + +Overrides the write RasterBase class method, which is a partial +function of the rasterio.DatasetReader.write method. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| +| `file_path` | str | File path used to save the Raster object. | _required_ | +| `driver` | str (default is 'GTiff'). | Name of GDAL driver used to save Raster data. | `'GTiff'` | +| `dtype` | str (opt | Optionally specify a numpy compatible data type when saving to file. If not specified, a data type is selected based on the data types of RasterLayers in the Raster object. | `None)` | +| `nodata` | any number (opt | Optionally assign a new nodata value when saving to file. If not specified a nodata value based on the minimum permissible value for the data types of RasterLayers in the Raster object is used. Note that this does not change the pixel nodata values of the raster, it only changes the metadata of what value represents a nodata pixel. | `None)` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|---------------------------|------------------------------------| | pyspatialml.raster.Raster | New Raster object from saved file. | \ No newline at end of file diff --git a/reference/RasterLayer.qmd b/reference/RasterLayer.qmd index f1a6684..fbfd154 100644 --- a/reference/RasterLayer.qmd +++ b/reference/RasterLayer.qmd @@ -1,205 +1,205 @@ -# RasterLayer { #pyspatialml.RasterLayer } - -`RasterLayer(self, band)` - -Represents a single raster band derived from a single or -multi-band raster dataset - -Simple wrapper around a rasterio.Band object with additional -methods. Used because the Rasterio.Band.ds.read method reads -all bands from a multi-band dataset, whereas the RasterLayer read -method only reads a single band. - -Methods encapsulated in RasterLayer objects represent those that -typically would only be applied to a single-band of a raster, i.e. -sieve-clump, distance to non-NaN pixels, or arithmetic operations -on individual layers. - -## Attributes - -| Name | Type | Description | -|---------------|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| -| bidx | int | The band index of the RasterLayer within the file dataset. | -| dtype | str | The data type of the RasterLayer. | -| ds | rasterio.rasterio.band | The underlying rasterio.band object. | -| name | str | A syntactically valid name for the RasterLayer. | -| file | str | The file path to the dataset. | -| nodata | any number | The number that is used to represent nodata pixels in the RasterLayer. | -| driver | str | The name of the GDAL format driver. | -| meta | dict | A python dict storing the RasterLayer metadata. | -| transform | affine.Affine object | The affine transform parameters. | -| count | int | Number of layers; always equal to 1. | -| shape | tuple | Shape of RasterLayer in (rows, columns) | -| width, height | int | The width (cols) and height (rows) of the dataset. | -| bounds | BoundingBox named tuple | A named tuple with left, bottom, right and top coordinates of the dataset. | -| cmap | str | The name of matplotlib map, or a custom matplotlib.cm.LinearSegmentedColormap or ListedColormap object. | -| norm | matplotlib.matplotlib.colors.matplotlib.colors.Normalize(opt) | A matplotlib.colors.Normalize to apply to the RasterLayer. This overides the norm attribute of the RasterLayer. | - -## Methods - -| Name | Description | -| --- | --- | -| [max](#pyspatialml.RasterLayer.max) | Maximum value. | -| [mean](#pyspatialml.RasterLayer.mean) | Mean value | -| [median](#pyspatialml.RasterLayer.median) | Median value | -| [min](#pyspatialml.RasterLayer.min) | Minimum value. | -| [plot](#pyspatialml.RasterLayer.plot) | Plot a RasterLayer using matplotlib.pyplot.imshow | -| [read](#pyspatialml.RasterLayer.read) | Read method for a single RasterLayer. | -| [stddev](#pyspatialml.RasterLayer.stddev) | Standard deviation | -| [write](#pyspatialml.RasterLayer.write) | Write method for a single RasterLayer. | - -### max { #pyspatialml.RasterLayer.max } - -`RasterLayer.max(max_pixels=10000)` - -Maximum value. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|--------|-------------------------------------------------------|-----------| -| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | - -#### Returns - -| Type | Description | -|---------------------|-------------------------------------------| -| numpy.numpy.float32 | The maximum value of the object's pixels. | - -### mean { #pyspatialml.RasterLayer.mean } - -`RasterLayer.mean(max_pixels=10000)` - -Mean value - -#### Parameters - -| Name | Type | Description | Default | -|--------------|--------|-------------------------------------------------------|-----------| -| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | - -#### Returns - -| Type | Description | -|---------------------|----------------------------------------| -| numpy.numpy.float32 | The mean value of the object's pixels. | - -### median { #pyspatialml.RasterLayer.median } - -`RasterLayer.median(max_pixels=10000)` - -Median value - -#### Parameters - -| Name | Type | Description | Default | -|--------------|--------|-------------------------------------------------------|-----------| -| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | - -#### Returns - -| Type | Description | -|---------------------|------------------------------------------| -| numpy.numpy.float32 | The medium value of the object's pixels. | - -### min { #pyspatialml.RasterLayer.min } - -`RasterLayer.min(max_pixels=10000)` - -Minimum value. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|--------|-------------------------------------------------------|-----------| -| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | - -#### Returns - -| Type | Description | -|---------------------|---------------------------------| -| numpy.numpy.float32 | The minimum value of the object | - -### plot { #pyspatialml.RasterLayer.plot } - -`RasterLayer.plot(cmap=None, norm=None, ax=None, cax=None, figsize=None, out_shape=(500, 500), categorical=None, legend=False, vmin=None, vmax=None, fig_kwds=None, legend_kwds=None)` - -Plot a RasterLayer using matplotlib.pyplot.imshow - -#### Parameters - -| Name | Type | Description | Default | -|---------------|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| -| `cmap` | str (default None) | The name of a colormap recognized by matplotlib. Overrides the cmap attribute of the RasterLayer. | `None` | -| `norm` | matplotlib.matplotlib.colors.matplotlib.colors.Normalize(opt) | A matplotlib.colors.Normalize to apply to the RasterLayer. This overrides the norm attribute of the RasterLayer. | `None` | -| `ax` | matplotlib.pyplot.Artist (optional | axes instance on which to draw to plot. | `None)` | -| `cax` | matplotlib.pyplot.Artist (optional | axes on which to draw the legend. | `None)` | -| `figsize` | tuple of integers (optional | Size of the matplotlib.figure.Figure. If the ax argument is given explicitly, figsize is ignored. | `None)` | -| `out_shape` | tuple | Number of rows, cols to read from the raster datasets for plotting. | `(500, 500)` | -| `categorical` | bool (optional | if True then the raster values will be considered to represent discrete values, otherwise they are considered to represent continuous values. This overrides the RasterLayer 'categorical' attribute. Setting the argument categorical to True is ignored if the RasterLayer.categorical is already True. | `False)` | -| `legend` | bool (optional | Whether to plot the legend. | `False)` | -| `vmin` | scale (optional | vmin and vmax define the data range that the colormap covers. By default, the colormap covers the complete value range of the supplied data. vmin, vmax are ignored if the norm parameter is used. | `None)` | -| `xmax` | scale (optional | vmin and vmax define the data range that the colormap covers. By default, the colormap covers the complete value range of the supplied data. vmin, vmax are ignored if the norm parameter is used. | `None)` | -| `fig_kwds` | dict (optional | Additional arguments to pass to the matplotlib.pyplot.figure call when creating the figure object. Ignored if ax is passed to the plot function. | `None)` | -| `legend_kwds` | dict (optional | Keyword arguments to pass to matplotlib.pyplot.colorbar(). | `None)` | - -#### Returns - -| Type | Description | -|--------------------------|---------------| -| matplotlib axes instance | | - -### read { #pyspatialml.RasterLayer.read } - -`RasterLayer.read(**kwargs)` - -Read method for a single RasterLayer. - -Reads the pixel values from a RasterLayer into a ndarray that -always will have two dimensions in the order of (rows, columns). - -#### Parameters - -| Name | Type | Description | Default | -|------------|-----------------------------------------------|-------------------------------------|-----------| -| `**kwargs` | named arguments that can be passed to the the | rasterio.DatasetReader.read method. | `{}` | - -### stddev { #pyspatialml.RasterLayer.stddev } - -`RasterLayer.stddev(max_pixels=10000)` - -Standard deviation - -#### Parameters - -| Name | Type | Description | Default | -|--------------|--------|-------------------------------------------------------|-----------| -| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | - -#### Returns - -| Type | Description | -|---------------------|------------------------------------------------| -| numpy.numpy.float32 | The standard deviation of the object's pixels. | - -### write { #pyspatialml.RasterLayer.write } - -`RasterLayer.write(file_path, driver='GTiff', dtype=None, nodata=None, **kwargs)` - -Write method for a single RasterLayer. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|------------------|----------------------------------------------------------------------------------------------------------------------------|------------| -| `file_path` | str(opt) | File path to save the dataset. | _required_ | -| `driver` | str | GDAL-compatible driver used for the file format. | `'GTiff'` | -| `dtype` | str(opt) | Numpy dtype used for the file. If omitted then the RasterLayer's dtype is used. | `None` | -| `nodata` | any number (opt) | A value used to represent the nodata pixels. If omitted then the RasterLayer's nodata value is used (if assigned already). | `None` | -| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | - -#### Returns - -| Type | Description | -|-------------------------------------|---------------| +# RasterLayer { #pyspatialml.RasterLayer } + +`RasterLayer(self, band)` + +Represents a single raster band derived from a single or +multi-band raster dataset + +Simple wrapper around a rasterio.Band object with additional +methods. Used because the Rasterio.Band.ds.read method reads +all bands from a multi-band dataset, whereas the RasterLayer read +method only reads a single band. + +Methods encapsulated in RasterLayer objects represent those that +typically would only be applied to a single-band of a raster, i.e. +sieve-clump, distance to non-NaN pixels, or arithmetic operations +on individual layers. + +## Attributes + +| Name | Type | Description | +|---------------|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| +| bidx | int | The band index of the RasterLayer within the file dataset. | +| dtype | str | The data type of the RasterLayer. | +| ds | rasterio.rasterio.band | The underlying rasterio.band object. | +| name | str | A syntactically valid name for the RasterLayer. | +| file | str | The file path to the dataset. | +| nodata | any number | The number that is used to represent nodata pixels in the RasterLayer. | +| driver | str | The name of the GDAL format driver. | +| meta | dict | A python dict storing the RasterLayer metadata. | +| transform | affine.Affine object | The affine transform parameters. | +| count | int | Number of layers; always equal to 1. | +| shape | tuple | Shape of RasterLayer in (rows, columns) | +| width, height | int | The width (cols) and height (rows) of the dataset. | +| bounds | BoundingBox named tuple | A named tuple with left, bottom, right and top coordinates of the dataset. | +| cmap | str | The name of matplotlib map, or a custom matplotlib.cm.LinearSegmentedColormap or ListedColormap object. | +| norm | matplotlib.matplotlib.colors.matplotlib.colors.Normalize(opt) | A matplotlib.colors.Normalize to apply to the RasterLayer. This overides the norm attribute of the RasterLayer. | + +## Methods + +| Name | Description | +| --- | --- | +| [max](#pyspatialml.RasterLayer.max) | Maximum value. | +| [mean](#pyspatialml.RasterLayer.mean) | Mean value | +| [median](#pyspatialml.RasterLayer.median) | Median value | +| [min](#pyspatialml.RasterLayer.min) | Minimum value. | +| [plot](#pyspatialml.RasterLayer.plot) | Plot a RasterLayer using matplotlib.pyplot.imshow | +| [read](#pyspatialml.RasterLayer.read) | Read method for a single RasterLayer. | +| [stddev](#pyspatialml.RasterLayer.stddev) | Standard deviation | +| [write](#pyspatialml.RasterLayer.write) | Write method for a single RasterLayer. | + +### max { #pyspatialml.RasterLayer.max } + +`RasterLayer.max(max_pixels=10000)` + +Maximum value. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|--------|-------------------------------------------------------|-----------| +| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | + +#### Returns + +| Type | Description | +|---------------------|-------------------------------------------| +| numpy.numpy.float32 | The maximum value of the object's pixels. | + +### mean { #pyspatialml.RasterLayer.mean } + +`RasterLayer.mean(max_pixels=10000)` + +Mean value + +#### Parameters + +| Name | Type | Description | Default | +|--------------|--------|-------------------------------------------------------|-----------| +| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | + +#### Returns + +| Type | Description | +|---------------------|----------------------------------------| +| numpy.numpy.float32 | The mean value of the object's pixels. | + +### median { #pyspatialml.RasterLayer.median } + +`RasterLayer.median(max_pixels=10000)` + +Median value + +#### Parameters + +| Name | Type | Description | Default | +|--------------|--------|-------------------------------------------------------|-----------| +| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | + +#### Returns + +| Type | Description | +|---------------------|------------------------------------------| +| numpy.numpy.float32 | The medium value of the object's pixels. | + +### min { #pyspatialml.RasterLayer.min } + +`RasterLayer.min(max_pixels=10000)` + +Minimum value. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|--------|-------------------------------------------------------|-----------| +| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | + +#### Returns + +| Type | Description | +|---------------------|---------------------------------| +| numpy.numpy.float32 | The minimum value of the object | + +### plot { #pyspatialml.RasterLayer.plot } + +`RasterLayer.plot(cmap=None, norm=None, ax=None, cax=None, figsize=None, out_shape=(500, 500), categorical=None, legend=False, vmin=None, vmax=None, fig_kwds=None, legend_kwds=None)` + +Plot a RasterLayer using matplotlib.pyplot.imshow + +#### Parameters + +| Name | Type | Description | Default | +|---------------|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| +| `cmap` | str (default None) | The name of a colormap recognized by matplotlib. Overrides the cmap attribute of the RasterLayer. | `None` | +| `norm` | matplotlib.matplotlib.colors.matplotlib.colors.Normalize(opt) | A matplotlib.colors.Normalize to apply to the RasterLayer. This overrides the norm attribute of the RasterLayer. | `None` | +| `ax` | matplotlib.pyplot.Artist (optional | axes instance on which to draw to plot. | `None)` | +| `cax` | matplotlib.pyplot.Artist (optional | axes on which to draw the legend. | `None)` | +| `figsize` | tuple of integers (optional | Size of the matplotlib.figure.Figure. If the ax argument is given explicitly, figsize is ignored. | `None)` | +| `out_shape` | tuple | Number of rows, cols to read from the raster datasets for plotting. | `(500, 500)` | +| `categorical` | bool (optional | if True then the raster values will be considered to represent discrete values, otherwise they are considered to represent continuous values. This overrides the RasterLayer 'categorical' attribute. Setting the argument categorical to True is ignored if the RasterLayer.categorical is already True. | `False)` | +| `legend` | bool (optional | Whether to plot the legend. | `False)` | +| `vmin` | scale (optional | vmin and vmax define the data range that the colormap covers. By default, the colormap covers the complete value range of the supplied data. vmin, vmax are ignored if the norm parameter is used. | `None)` | +| `xmax` | scale (optional | vmin and vmax define the data range that the colormap covers. By default, the colormap covers the complete value range of the supplied data. vmin, vmax are ignored if the norm parameter is used. | `None)` | +| `fig_kwds` | dict (optional | Additional arguments to pass to the matplotlib.pyplot.figure call when creating the figure object. Ignored if ax is passed to the plot function. | `None)` | +| `legend_kwds` | dict (optional | Keyword arguments to pass to matplotlib.pyplot.colorbar(). | `None)` | + +#### Returns + +| Type | Description | +|--------------------------|---------------| +| matplotlib axes instance | | + +### read { #pyspatialml.RasterLayer.read } + +`RasterLayer.read(**kwargs)` + +Read method for a single RasterLayer. + +Reads the pixel values from a RasterLayer into a ndarray that +always will have two dimensions in the order of (rows, columns). + +#### Parameters + +| Name | Type | Description | Default | +|------------|-----------------------------------------------|-------------------------------------|-----------| +| `**kwargs` | named arguments that can be passed to the the | rasterio.DatasetReader.read method. | `{}` | + +### stddev { #pyspatialml.RasterLayer.stddev } + +`RasterLayer.stddev(max_pixels=10000)` + +Standard deviation + +#### Parameters + +| Name | Type | Description | Default | +|--------------|--------|-------------------------------------------------------|-----------| +| `max_pixels` | int | Number of pixels used to inform statistical estimate. | `10000` | + +#### Returns + +| Type | Description | +|---------------------|------------------------------------------------| +| numpy.numpy.float32 | The standard deviation of the object's pixels. | + +### write { #pyspatialml.RasterLayer.write } + +`RasterLayer.write(file_path, driver='GTiff', dtype=None, nodata=None, **kwargs)` + +Write method for a single RasterLayer. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|------------------|----------------------------------------------------------------------------------------------------------------------------|------------| +| `file_path` | str(opt) | File path to save the dataset. | _required_ | +| `driver` | str | GDAL-compatible driver used for the file format. | `'GTiff'` | +| `dtype` | str(opt) | Numpy dtype used for the file. If omitted then the RasterLayer's dtype is used. | `None` | +| `nodata` | any number (opt) | A value used to represent the nodata pixels. If omitted then the RasterLayer's nodata value is used (if assigned already). | `None` | +| `kwargs` | opt | Optional named arguments to pass to the format drivers. For example can be `compress="deflate"` to add compression. | `{}` | + +#### Returns + +| Type | Description | +|-------------------------------------|---------------| | pyspatialml.pyspatialml.RasterLayer | | \ No newline at end of file diff --git a/reference/index.qmd b/reference/index.qmd index 67141f7..c7ef519 100644 --- a/reference/index.qmd +++ b/reference/index.qmd @@ -1,26 +1,26 @@ -# Function reference {.doc .doc-index} - -## Raster datasets - -Raster is a class for reading and writing raster datasets - -| | | -| --- | --- | -| [Raster](Raster.qmd#pyspatialml.Raster) | Creates a collection of file-based GDAL-supported raster | -| [RasterLayer](RasterLayer.qmd#pyspatialml.RasterLayer) | Represents a single raster band derived from a single or | - -## Vector tools - -Tools for working with vector datasets - -| | | -| --- | --- | -| [vector](vector.qmd#pyspatialml.vector) | | - -## Preprocessing - -Preprocessing tools for raster datasets - -| | | -| --- | --- | +# Function reference {.doc .doc-index} + +## Raster datasets + +Raster is a class for reading and writing raster datasets + +| | | +| --- | --- | +| [Raster](Raster.qmd#pyspatialml.Raster) | Creates a collection of file-based GDAL-supported raster | +| [RasterLayer](RasterLayer.qmd#pyspatialml.RasterLayer) | Represents a single raster band derived from a single or | + +## Vector tools + +Tools for working with vector datasets + +| | | +| --- | --- | +| [vector](vector.qmd#pyspatialml.vector) | | + +## Preprocessing + +Preprocessing tools for raster datasets + +| | | +| --- | --- | | [preprocessing](preprocessing.qmd#pyspatialml.preprocessing) | | \ No newline at end of file diff --git a/reference/preprocessing.qmd b/reference/preprocessing.qmd index 124bf85..f429376 100644 --- a/reference/preprocessing.qmd +++ b/reference/preprocessing.qmd @@ -1,119 +1,119 @@ -# preprocessing { #pyspatialml.preprocessing } - -`preprocessing` - - - -## Functions - -| Name | Description | -| --- | --- | -| [distance_to_corners](#pyspatialml.preprocessing.distance_to_corners) | Generate buffer distances to corner and centre coordinates of raster | -| [distance_to_samples](#pyspatialml.preprocessing.distance_to_samples) | Generate buffer distances to x,y coordinates. | -| [one_hot_encode](#pyspatialml.preprocessing.one_hot_encode) | One-hot encoding of a RasterLayer. | -| [rotated_coordinates](#pyspatialml.preprocessing.rotated_coordinates) | Generate 2d arrays with n_angles rotated coordinates. | -| [xy_coordinates](#pyspatialml.preprocessing.xy_coordinates) | Fill 2d arrays with their x,y indices. | - -### distance_to_corners { #pyspatialml.preprocessing.distance_to_corners } - -`preprocessing.distance_to_corners(layer, file_path, driver='GTiff')` - -Generate buffer distances to corner and centre coordinates of raster -extent. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|----------------------------------------------------|--------------------------------------------------|------------| -| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | | _required_ | -| `file_path` | str | File path to save to the resulting Raster object | _required_ | -| `driver` | (str, optional.optional.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | - -#### Returns - -| Type | Description | -|---------------------------|---------------| -| pyspatialml.Raster object | | - -### distance_to_samples { #pyspatialml.preprocessing.distance_to_samples } - -`preprocessing.distance_to_samples(layer, file_path, rows, cols, driver='GTiff')` - -Generate buffer distances to x,y coordinates. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|----------------------------------------------------|---------------------------------------------------|------------| -| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | -| `file_path` | str | File path to save to the resulting Raster object. | _required_ | -| `rows` | 1d numpy array | array of row indexes. | _required_ | -| `cols` | 1d numpy array | array of column indexes. | _required_ | -| `driver` | str | GDAL driver to use to save raster. | `'GTiff'` | - -#### Returns - -| Type | Description | -|---------------------------|---------------| -| pyspatialml.Raster object | | - -### one_hot_encode { #pyspatialml.preprocessing.one_hot_encode } - -`preprocessing.one_hot_encode(layer, file_path, categories=None, driver='GTiff')` - -One-hot encoding of a RasterLayer. - -#### Parameters - -| Name | Type | Description | Default | -|--------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------|------------| -| `layer` | pyspatialml.pyspatialml.RasterLayer | Containing categories to perform one-hot encoding on. | _required_ | -| `file_path` | str | File path to save one-hot encoded raster. | _required_ | -| `categories` | (list, ndarray) | Optional list of categories to extract. Default performs one-hot encoding on all categorical values in the input layer. | `None` | -| `driver` | (str, options.options.Default is GTiff) | GDAL-compatible driver. | `'GTiff'` | - -#### Returns - -| Type | Description | -|--------------------------------|--------------------------------------------------------------------| -| pyspatialml.pyspatialml.Raster | Each categorical value is encoded as a layer with a Raster object. | - -### rotated_coordinates { #pyspatialml.preprocessing.rotated_coordinates } - -`preprocessing.rotated_coordinates(layer, file_path, n_angles=8, driver='GTiff')` - -Generate 2d arrays with n_angles rotated coordinates. - -#### Parameters - -| Name | Type | Description | Default | -|------------|----------------------------------------------------|--------------------------------------------------|------------| -| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | -| `n_angles` | (int, optional.optional.Default is 8) | Number of angles to rotate coordinate system by. | `8` | -| `driver` | (str, optional.optional.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | - -#### Returns - -| Type | Description | -|--------------------------------|---------------| -| pyspatialml.pyspatialml.Raster | | - -### xy_coordinates { #pyspatialml.preprocessing.xy_coordinates } - -`preprocessing.xy_coordinates(layer, file_path, driver='GTiff')` - -Fill 2d arrays with their x,y indices. - -#### Parameters - -| Name | Type | Description | Default | -|-------------|----------------------------------------------------|----------------------------------------------------|------------| -| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | -| `file_path` | str | File path to save to the resulting Raster object.s | _required_ | -| `driver` | (str, options.options.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | - -#### Returns - -| Type | Description | -|---------------------------|---------------| +# preprocessing { #pyspatialml.preprocessing } + +`preprocessing` + + + +## Functions + +| Name | Description | +| --- | --- | +| [distance_to_corners](#pyspatialml.preprocessing.distance_to_corners) | Generate buffer distances to corner and centre coordinates of raster | +| [distance_to_samples](#pyspatialml.preprocessing.distance_to_samples) | Generate buffer distances to x,y coordinates. | +| [one_hot_encode](#pyspatialml.preprocessing.one_hot_encode) | One-hot encoding of a RasterLayer. | +| [rotated_coordinates](#pyspatialml.preprocessing.rotated_coordinates) | Generate 2d arrays with n_angles rotated coordinates. | +| [xy_coordinates](#pyspatialml.preprocessing.xy_coordinates) | Fill 2d arrays with their x,y indices. | + +### distance_to_corners { #pyspatialml.preprocessing.distance_to_corners } + +`preprocessing.distance_to_corners(layer, file_path, driver='GTiff')` + +Generate buffer distances to corner and centre coordinates of raster +extent. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|----------------------------------------------------|--------------------------------------------------|------------| +| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | | _required_ | +| `file_path` | str | File path to save to the resulting Raster object | _required_ | +| `driver` | (str, optional.optional.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | + +#### Returns + +| Type | Description | +|---------------------------|---------------| +| pyspatialml.Raster object | | + +### distance_to_samples { #pyspatialml.preprocessing.distance_to_samples } + +`preprocessing.distance_to_samples(layer, file_path, rows, cols, driver='GTiff')` + +Generate buffer distances to x,y coordinates. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|----------------------------------------------------|---------------------------------------------------|------------| +| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | +| `file_path` | str | File path to save to the resulting Raster object. | _required_ | +| `rows` | 1d numpy array | array of row indexes. | _required_ | +| `cols` | 1d numpy array | array of column indexes. | _required_ | +| `driver` | str | GDAL driver to use to save raster. | `'GTiff'` | + +#### Returns + +| Type | Description | +|---------------------------|---------------| +| pyspatialml.Raster object | | + +### one_hot_encode { #pyspatialml.preprocessing.one_hot_encode } + +`preprocessing.one_hot_encode(layer, file_path, categories=None, driver='GTiff')` + +One-hot encoding of a RasterLayer. + +#### Parameters + +| Name | Type | Description | Default | +|--------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------|------------| +| `layer` | pyspatialml.pyspatialml.RasterLayer | Containing categories to perform one-hot encoding on. | _required_ | +| `file_path` | str | File path to save one-hot encoded raster. | _required_ | +| `categories` | (list, ndarray) | Optional list of categories to extract. Default performs one-hot encoding on all categorical values in the input layer. | `None` | +| `driver` | (str, options.options.Default is GTiff) | GDAL-compatible driver. | `'GTiff'` | + +#### Returns + +| Type | Description | +|--------------------------------|--------------------------------------------------------------------| +| pyspatialml.pyspatialml.Raster | Each categorical value is encoded as a layer with a Raster object. | + +### rotated_coordinates { #pyspatialml.preprocessing.rotated_coordinates } + +`preprocessing.rotated_coordinates(layer, file_path, n_angles=8, driver='GTiff')` + +Generate 2d arrays with n_angles rotated coordinates. + +#### Parameters + +| Name | Type | Description | Default | +|------------|----------------------------------------------------|--------------------------------------------------|------------| +| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | +| `n_angles` | (int, optional.optional.Default is 8) | Number of angles to rotate coordinate system by. | `8` | +| `driver` | (str, optional.optional.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | + +#### Returns + +| Type | Description | +|--------------------------------|---------------| +| pyspatialml.pyspatialml.Raster | | + +### xy_coordinates { #pyspatialml.preprocessing.xy_coordinates } + +`preprocessing.xy_coordinates(layer, file_path, driver='GTiff')` + +Fill 2d arrays with their x,y indices. + +#### Parameters + +| Name | Type | Description | Default | +|-------------|----------------------------------------------------|----------------------------------------------------|------------| +| `layer` | pyspatialml.RasterLayer, or rasterio.DatasetReader | RasterLayer to use as a template. | _required_ | +| `file_path` | str | File path to save to the resulting Raster object.s | _required_ | +| `driver` | (str, options.options.Default is GTiff) | GDAL driver to use to save raster. | `'GTiff'` | + +#### Returns + +| Type | Description | +|---------------------------|---------------| | pyspatialml.Raster object | | \ No newline at end of file diff --git a/reference/vector.qmd b/reference/vector.qmd index 6721953..1118946 100644 --- a/reference/vector.qmd +++ b/reference/vector.qmd @@ -1,51 +1,51 @@ -# vector { #pyspatialml.vector } - -`vector` - - - -## Functions - -| Name | Description | -| --- | --- | -| [filter_points](#pyspatialml.vector.filter_points) | Filter points in geodataframe using a minimum distance buffer. | -| [get_random_point_in_polygon](#pyspatialml.vector.get_random_point_in_polygon) | Generates random shapely Point geometry objects within a single | - -### filter_points { #pyspatialml.vector.filter_points } - -`vector.filter_points(gdf, min_dist=0, remove='first')` - -Filter points in geodataframe using a minimum distance buffer. - -#### Parameters - -| Name | Type | Description | Default | -|------------|-------------------------------------|------------------------------------------------------------------------|------------| -| `gdf` | Geopandas GeoDataFrame | Containing point geometries. | _required_ | -| `min_dist` | (int or float, optional(default=0)) | Minimum distance by which to filter out closely spaced points. | `0` | -| `remove` | (str, optional(default=first)) | Optionally choose to remove 'first' occurrences or 'last' occurrences. | `'first'` | - -#### Returns - -| Type | Description | -|---------------|----------------------------------| -| 2d array-like | Numpy array filtered coordinates | - -### get_random_point_in_polygon { #pyspatialml.vector.get_random_point_in_polygon } - -`vector.get_random_point_in_polygon(poly)` - -Generates random shapely Point geometry objects within a single -shapely Polygon object. - -#### Parameters - -| Name | Type | Description | Default | -|--------|------------------------|---------------|------------| -| `poly` | Shapely Polygon object | | _required_ | - -#### Returns - -| Type | Description | -|----------------------|---------------| +# vector { #pyspatialml.vector } + +`vector` + + + +## Functions + +| Name | Description | +| --- | --- | +| [filter_points](#pyspatialml.vector.filter_points) | Filter points in geodataframe using a minimum distance buffer. | +| [get_random_point_in_polygon](#pyspatialml.vector.get_random_point_in_polygon) | Generates random shapely Point geometry objects within a single | + +### filter_points { #pyspatialml.vector.filter_points } + +`vector.filter_points(gdf, min_dist=0, remove='first')` + +Filter points in geodataframe using a minimum distance buffer. + +#### Parameters + +| Name | Type | Description | Default | +|------------|-------------------------------------|------------------------------------------------------------------------|------------| +| `gdf` | Geopandas GeoDataFrame | Containing point geometries. | _required_ | +| `min_dist` | (int or float, optional(default=0)) | Minimum distance by which to filter out closely spaced points. | `0` | +| `remove` | (str, optional(default=first)) | Optionally choose to remove 'first' occurrences or 'last' occurrences. | `'first'` | + +#### Returns + +| Type | Description | +|---------------|----------------------------------| +| 2d array-like | Numpy array filtered coordinates | + +### get_random_point_in_polygon { #pyspatialml.vector.get_random_point_in_polygon } + +`vector.get_random_point_in_polygon(poly)` + +Generates random shapely Point geometry objects within a single +shapely Polygon object. + +#### Parameters + +| Name | Type | Description | Default | +|--------|------------------------|---------------|------------| +| `poly` | Shapely Polygon object | | _required_ | + +#### Returns + +| Type | Description | +|----------------------|---------------| | Shapely Point object | | \ No newline at end of file diff --git a/tests/test_alter.py b/tests/test_alter.py index 1c031d1..de13c9f 100644 --- a/tests/test_alter.py +++ b/tests/test_alter.py @@ -1,26 +1,26 @@ -from unittest import TestCase - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster -import geopandas as gpd -from sklearn.preprocessing import StandardScaler - - -class TestAlter(TestCase): - def setUp(self) -> None: - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.stack = Raster(predictors) - points = gpd.read_file(nc.points) - data = self.stack.extract_vector(points) - self.data = data.dropna() - - def tearDown(self) -> None: - self.stack.close() - - def test_alter(self): - scaler = StandardScaler() - scaler.fit(self.data.drop(columns=["geometry"]).values) - out = self.stack.alter(scaler) - - self.assertIsInstance(out, Raster) - self.assertEqual(out.shape, self.stack.shape) +from unittest import TestCase + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster +import geopandas as gpd +from sklearn.preprocessing import StandardScaler + + +class TestAlter(TestCase): + def setUp(self) -> None: + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.stack = Raster(predictors) + points = gpd.read_file(nc.points) + data = self.stack.extract_vector(points) + self.data = data.dropna() + + def tearDown(self) -> None: + self.stack.close() + + def test_alter(self): + scaler = StandardScaler() + scaler.fit(self.data.drop(columns=["geometry"]).values) + out = self.stack.alter(scaler) + + self.assertIsInstance(out, Raster) + self.assertEqual(out.shape, self.stack.shape) diff --git a/tests/test_append.py b/tests/test_append.py index 8943135..85cf796 100644 --- a/tests/test_append.py +++ b/tests/test_append.py @@ -1,78 +1,78 @@ -from unittest import TestCase - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestAppend(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - - def test_append_inplace(self): - """Append another Raster containing a single layer with identical name - - This test should cause the Raster object to automatically rename the - duplicated names as "lsat7_2000_70_1", "lsat7_2000_70_2", etc. - - Appending a multi-band raster should result in a new layer with the - multi-band name "landsat_multiband_1", "landsat_multiband_2", etc. - - A list of Rasters can be passed to append() to append multiple rasters - """ - # append a single band raster with the same name - stack = Raster(self.predictors) - band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() - stack.append(Raster(nc.band7), in_place=True) - - self.assertEqual(list(stack.names)[5], "lsat7_2000_70_1") - self.assertEqual(list(stack.names)[-1], "lsat7_2000_70_2") - self.assertEqual( - stack.lsat7_2000_70_1.read(masked=True).mean(), - stack.lsat7_2000_70_2.read(masked=True).mean(), - band7_mean, - ) - - # append a multiband raster - stack = Raster(self.predictors) - stack.append(Raster(nc.multiband), in_place=True) - self.assertEqual(list(stack.names)[6], "landsat_multiband_1") - stack.close() - - # append multiple rasters - stack = Raster(self.predictors) - stack.append([Raster(nc.band5), Raster(nc.band7)], in_place=True) - self.assertEqual(stack.count, 8) - - def test_append_with_copy(self): - """Same tests as above but create a new Raster rather than append - in place - """ - # append another Raster containing a single layer with identical name - stack = Raster(self.predictors) - band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() - result = stack.append(Raster(nc.band7), in_place=False) - - # check that original is untouched - self.assertEqual(stack.count, 6) - - # check that result contains appended raster - self.assertEqual(list(result.names)[5], "lsat7_2000_70_1") - self.assertEqual(list(result.names)[-1], "lsat7_2000_70_2") - - # check that band 7 stats are the same after appending - self.assertEqual( - result.lsat7_2000_70_1.read(masked=True).mean(), - result.lsat7_2000_70_2.read(masked=True).mean(), - band7_mean, - ) - - # append a multiband raster - result = stack.append(Raster(nc.multiband), in_place=False) - self.assertEqual(list(result.names)[6], "landsat_multiband_1") - stack.close() - - # append multiple rasters - stack = Raster(self.predictors) - new_stack = stack.append([Raster(nc.band5), Raster(nc.band7)], in_place=False) - self.assertEqual(new_stack.count, 8) +from unittest import TestCase + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestAppend(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + + def test_append_inplace(self): + """Append another Raster containing a single layer with identical name + + This test should cause the Raster object to automatically rename the + duplicated names as "lsat7_2000_70_1", "lsat7_2000_70_2", etc. + + Appending a multi-band raster should result in a new layer with the + multi-band name "landsat_multiband_1", "landsat_multiband_2", etc. + + A list of Rasters can be passed to append() to append multiple rasters + """ + # append a single band raster with the same name + stack = Raster(self.predictors) + band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() + stack.append(Raster(nc.band7), in_place=True) + + self.assertEqual(list(stack.names)[5], "lsat7_2000_70_1") + self.assertEqual(list(stack.names)[-1], "lsat7_2000_70_2") + self.assertEqual( + stack.lsat7_2000_70_1.read(masked=True).mean(), + stack.lsat7_2000_70_2.read(masked=True).mean(), + band7_mean, + ) + + # append a multiband raster + stack = Raster(self.predictors) + stack.append(Raster(nc.multiband), in_place=True) + self.assertEqual(list(stack.names)[6], "landsat_multiband_1") + stack.close() + + # append multiple rasters + stack = Raster(self.predictors) + stack.append([Raster(nc.band5), Raster(nc.band7)], in_place=True) + self.assertEqual(stack.count, 8) + + def test_append_with_copy(self): + """Same tests as above but create a new Raster rather than append + in place + """ + # append another Raster containing a single layer with identical name + stack = Raster(self.predictors) + band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() + result = stack.append(Raster(nc.band7), in_place=False) + + # check that original is untouched + self.assertEqual(stack.count, 6) + + # check that result contains appended raster + self.assertEqual(list(result.names)[5], "lsat7_2000_70_1") + self.assertEqual(list(result.names)[-1], "lsat7_2000_70_2") + + # check that band 7 stats are the same after appending + self.assertEqual( + result.lsat7_2000_70_1.read(masked=True).mean(), + result.lsat7_2000_70_2.read(masked=True).mean(), + band7_mean, + ) + + # append a multiband raster + result = stack.append(Raster(nc.multiband), in_place=False) + self.assertEqual(list(result.names)[6], "landsat_multiband_1") + stack.close() + + # append multiple rasters + stack = Raster(self.predictors) + new_stack = stack.append([Raster(nc.band5), Raster(nc.band7)], in_place=False) + self.assertEqual(new_stack.count, 8) diff --git a/tests/test_apply.py b/tests/test_apply.py index f7d6145..4a971ea 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1,65 +1,65 @@ -from unittest import TestCase - -import numpy as np - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestCalc(TestCase): - def setUp(self) -> None: - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.stack = Raster(predictors) - self.result = None - - def tearDown(self) -> None: - self.stack.close() - self.result.close() - self.stack = None - self.result = None - - def test_calc_with_2d_output(self): - def compute_outputs_2d_array(arr): - return arr[0, :, :] + arr[1, :, :] - - self.result = self.stack.apply(compute_outputs_2d_array) - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, 1) - self.assertEqual(self.result.read(masked=True).count(), 183418) - - def test_calc_with_2d_output_coerce_dtype(self): - def compute_outputs_2d_array(arr): - return arr[0, :, :] + arr[1, :, :] - - self.result = self.stack.apply(compute_outputs_2d_array, dtype=np.int16) - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, 1) - self.assertEqual(self.result.read(masked=True).count(), 183418) - - def test_calc_with_3d_output(self): - def compute_outputs_3d_array(arr): - arr[0, :, :] = arr[0, :, :] + arr[1, ::] - return arr - - self.result = self.stack.apply(compute_outputs_3d_array) - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, 6) - self.assertEqual(self.result.read(masked=True).count(), 1052182) - - def test_calc_with_multiprocessing(self): - def compute_outputs_2d_array(arr): - return arr[0, :, :] + arr[1, :, :] - - self.result = self.stack.apply(compute_outputs_2d_array) - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, 1) - self.assertEqual(self.result.read(masked=True).count(), 183418) - - def test_calc_in_memory(self): - def compute_outputs_2d_array(arr): - return arr[0, :, :] + arr[1, :, :] - - self.result = self.stack.apply(compute_outputs_2d_array, in_memory=True) - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, 1) - self.assertEqual(self.result.read(masked=True).count(), 183418) +from unittest import TestCase + +import numpy as np + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestCalc(TestCase): + def setUp(self) -> None: + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.stack = Raster(predictors) + self.result = None + + def tearDown(self) -> None: + self.stack.close() + self.result.close() + self.stack = None + self.result = None + + def test_calc_with_2d_output(self): + def compute_outputs_2d_array(arr): + return arr[0, :, :] + arr[1, :, :] + + self.result = self.stack.apply(compute_outputs_2d_array) + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, 1) + self.assertEqual(self.result.read(masked=True).count(), 183418) + + def test_calc_with_2d_output_coerce_dtype(self): + def compute_outputs_2d_array(arr): + return arr[0, :, :] + arr[1, :, :] + + self.result = self.stack.apply(compute_outputs_2d_array, dtype=np.int16) + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, 1) + self.assertEqual(self.result.read(masked=True).count(), 183418) + + def test_calc_with_3d_output(self): + def compute_outputs_3d_array(arr): + arr[0, :, :] = arr[0, :, :] + arr[1, ::] + return arr + + self.result = self.stack.apply(compute_outputs_3d_array) + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, 6) + self.assertEqual(self.result.read(masked=True).count(), 1052182) + + def test_calc_with_multiprocessing(self): + def compute_outputs_2d_array(arr): + return arr[0, :, :] + arr[1, :, :] + + self.result = self.stack.apply(compute_outputs_2d_array) + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, 1) + self.assertEqual(self.result.read(masked=True).count(), 183418) + + def test_calc_in_memory(self): + def compute_outputs_2d_array(arr): + return arr[0, :, :] + arr[1, :, :] + + self.result = self.stack.apply(compute_outputs_2d_array, in_memory=True) + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, 1) + self.assertEqual(self.result.read(masked=True).count(), 183418) diff --git a/tests/test_band_math.py b/tests/test_band_math.py index 7e4b305..87b20b6 100644 --- a/tests/test_band_math.py +++ b/tests/test_band_math.py @@ -1,33 +1,33 @@ -import numpy as np -import unittest -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestArith(unittest.TestCase): - def setUp(self) -> None: - arr = np.zeros((3, 100, 100)) - arr[1,:,:] = 1 - arr[2,:,:] = 2 - self.obj = Raster(arr) - self.obj.names = ["band1", "band2", "band3"] - - def test_scalar(self): - addition = self.obj.iloc[0] + 100 - self.assertEqual(addition.min(), 100) - - division = addition / 10 - self.assertEqual(division.min(), 10.0) - - multiplication = self.obj.iloc[1] * 100 - self.assertEqual(multiplication.min(), 100) - - def test_rasterlayer(self): - addition = self.obj.iloc[0] + self.obj.iloc[1] - self.assertEqual(addition.min(), 1.0) - - multiplication = self.obj.iloc[1] * self.obj.iloc[2] - self.assertEqual(multiplication.min(), 2) - - def test_raster(self): - pass +import numpy as np +import unittest +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestArith(unittest.TestCase): + def setUp(self) -> None: + arr = np.zeros((3, 100, 100)) + arr[1,:,:] = 1 + arr[2,:,:] = 2 + self.obj = Raster(arr) + self.obj.names = ["band1", "band2", "band3"] + + def test_scalar(self): + addition = self.obj.iloc[0] + 100 + self.assertEqual(addition.min(), 100) + + division = addition / 10 + self.assertEqual(division.min(), 10.0) + + multiplication = self.obj.iloc[1] * 100 + self.assertEqual(multiplication.min(), 100) + + def test_rasterlayer(self): + addition = self.obj.iloc[0] + self.obj.iloc[1] + self.assertEqual(addition.min(), 1.0) + + multiplication = self.obj.iloc[1] * self.obj.iloc[2] + self.assertEqual(multiplication.min(), 2) + + def test_raster(self): + pass diff --git a/tests/test_band_names.py b/tests/test_band_names.py index e7c8bc5..66ba246 100644 --- a/tests/test_band_names.py +++ b/tests/test_band_names.py @@ -1,53 +1,53 @@ -import os -from unittest import TestCase - -import rasterio -import tempfile -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestNames(TestCase): - """Test the initiation of a Raster object when the file raster dataset - contains band names - """ - def setUp(self) -> None: - """Create a temporary file with a raster dataset with band names - """ - with rasterio.open(nc.multiband) as src: - self.descriptions = ["band_1", "band_2", "band_3", "band_4", "band_5"] - - self.fp = tempfile.NamedTemporaryFile(suffix=".tif").name - - with rasterio.open(self.fp, "w", **src.meta) as dst: - for i, band in enumerate(self.descriptions, start=1): - dst.write_band(i, src.read(i)) - dst.set_band_description(i, band) - - def tearDown(self) -> None: - os.remove(self.fp) - - def test_names_from_file(self) -> None: - """Test the initiation of a Raster object from a file when the file raster - dataset contains band descriptions""" - r = Raster(self.fp) - self.assertEqual(list(r.names), self.descriptions) - - def test_names_from_rasterio(self) -> None: - """Test the initiation of a Raster object from a rasterio.DatasetReader - object when the file raster dataset has band descriptions - """ - with rasterio.open(self.fp) as src: - r = Raster(src) - self.assertEqual(list(r.names), self.descriptions) - - def test_names_subsetting(self) -> None: - """Test that the names of the bands are preserved when subsetting a raster - """ - r = Raster(self.fp) - subset = r.iloc[[0, 1]] - self.assertEqual(list(subset.names), self.descriptions[0:2]) - - new = r.copy(["band_1", "band_2"]) - new["band_3"] = r["band_3"] - self.assertEqual(list(new.names), self.descriptions[0:3]) +import os +from unittest import TestCase + +import rasterio +import tempfile +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestNames(TestCase): + """Test the initiation of a Raster object when the file raster dataset + contains band names + """ + def setUp(self) -> None: + """Create a temporary file with a raster dataset with band names + """ + with rasterio.open(nc.multiband) as src: + self.descriptions = ["band_1", "band_2", "band_3", "band_4", "band_5"] + + self.fp = tempfile.NamedTemporaryFile(suffix=".tif").name + + with rasterio.open(self.fp, "w", **src.meta) as dst: + for i, band in enumerate(self.descriptions, start=1): + dst.write_band(i, src.read(i)) + dst.set_band_description(i, band) + + def tearDown(self) -> None: + os.remove(self.fp) + + def test_names_from_file(self) -> None: + """Test the initiation of a Raster object from a file when the file raster + dataset contains band descriptions""" + r = Raster(self.fp) + self.assertEqual(list(r.names), self.descriptions) + + def test_names_from_rasterio(self) -> None: + """Test the initiation of a Raster object from a rasterio.DatasetReader + object when the file raster dataset has band descriptions + """ + with rasterio.open(self.fp) as src: + r = Raster(src) + self.assertEqual(list(r.names), self.descriptions) + + def test_names_subsetting(self) -> None: + """Test that the names of the bands are preserved when subsetting a raster + """ + r = Raster(self.fp) + subset = r.iloc[[0, 1]] + self.assertEqual(list(subset.names), self.descriptions[0:2]) + + new = r.copy(["band_1", "band_2"]) + new["band_3"] = r["band_3"] + self.assertEqual(list(new.names), self.descriptions[0:3]) diff --git a/tests/test_crop.py b/tests/test_crop.py index 5315307..53dea96 100644 --- a/tests/test_crop.py +++ b/tests/test_crop.py @@ -1,39 +1,39 @@ -from unittest import TestCase - -import geopandas as gpd - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestToCrs(TestCase): - def setUp(self) -> None: - # inputs - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - self.stack = Raster(self.predictors) - training_py = gpd.read_file(nc.polygons) - self.crop_bounds = training_py.loc[0, "geometry"].bounds - - # outputs - self.cropped = None - - def tearDown(self) -> None: - self.stack.close() - self.cropped.close() - - def test_crop_defaults(self): - self.cropped = self.stack.crop(self.crop_bounds) - - # check raster object - self.assertIsInstance(self.cropped, Raster) - self.assertEqual(self.cropped.count, self.stack.count) - self.assertEqual(self.cropped.read(masked=True).count(), 1440) - - # test nodata value is recognized - self.assertEqual(self.cropped.read(masked=True).min(), 35.0) - self.assertEqual(self.cropped.read(masked=True).max(), 168.0) - - def test_crop_in_memory(self): - self.cropped = self.stack.crop(self.crop_bounds, in_memory=True) - self.assertIsInstance(self.cropped, Raster) +from unittest import TestCase + +import geopandas as gpd + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestToCrs(TestCase): + def setUp(self) -> None: + # inputs + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + self.stack = Raster(self.predictors) + training_py = gpd.read_file(nc.polygons) + self.crop_bounds = training_py.loc[0, "geometry"].bounds + + # outputs + self.cropped = None + + def tearDown(self) -> None: + self.stack.close() + self.cropped.close() + + def test_crop_defaults(self): + self.cropped = self.stack.crop(self.crop_bounds) + + # check raster object + self.assertIsInstance(self.cropped, Raster) + self.assertEqual(self.cropped.count, self.stack.count) + self.assertEqual(self.cropped.read(masked=True).count(), 1440) + + # test nodata value is recognized + self.assertEqual(self.cropped.read(masked=True).min(), 35.0) + self.assertEqual(self.cropped.read(masked=True).max(), 168.0) + + def test_crop_in_memory(self): + self.cropped = self.stack.crop(self.crop_bounds, in_memory=True) + self.assertIsInstance(self.cropped, Raster) diff --git a/tests/test_drop.py b/tests/test_drop.py index a18401c..ff1a5f4 100644 --- a/tests/test_drop.py +++ b/tests/test_drop.py @@ -1,59 +1,59 @@ -from unittest import TestCase - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestDrop(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - - def test_drop_inplace(self): - stack = Raster(self.predictors) - stack.drop(labels="lsat7_2000_50", in_place=True) - - # check that Raster object is returned - self.assertIsInstance(stack, Raster) - - # check that RasterLayer has been dropped - self.assertEqual(stack.count, 5) - self.assertNotIn("lsat7_2000_50", stack.names) - stack.close() - - def test_drop_with_copy(self): - stack = Raster(self.predictors) - names = stack.names - result = stack.drop(labels="lsat7_2000_50", in_place=False) - - # check that Raster object is returned - self.assertIsInstance(result, Raster) - - # check that RasterLayer has been dropped - self.assertEqual(result.count, 5) - self.assertNotIn("lsat7_2000_50", result.names) - - # check that original raster is unaffected - self.assertEqual(stack.count, 6) - self.assertEqual(stack.names, names) - stack.close() - result.close() - - def test_drop_in_memory(self): - stack = Raster(self.predictors) - names = stack.names - - result = stack.intersect(in_memory=True) - result = stack.drop(labels="lsat7_2000_50", in_place=False) - - # check that Raster object is returned - self.assertIsInstance(result, Raster) - - # check that RasterLayer has been dropped - self.assertEqual(result.count, 5) - self.assertNotIn("lsat7_2000_50", result.names) - - # check that original raster is unaffected - self.assertEqual(stack.count, 6) - self.assertEqual(stack.names, names) - stack.close() +from unittest import TestCase + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestDrop(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + + def test_drop_inplace(self): + stack = Raster(self.predictors) + stack.drop(labels="lsat7_2000_50", in_place=True) + + # check that Raster object is returned + self.assertIsInstance(stack, Raster) + + # check that RasterLayer has been dropped + self.assertEqual(stack.count, 5) + self.assertNotIn("lsat7_2000_50", stack.names) + stack.close() + + def test_drop_with_copy(self): + stack = Raster(self.predictors) + names = stack.names + result = stack.drop(labels="lsat7_2000_50", in_place=False) + + # check that Raster object is returned + self.assertIsInstance(result, Raster) + + # check that RasterLayer has been dropped + self.assertEqual(result.count, 5) + self.assertNotIn("lsat7_2000_50", result.names) + + # check that original raster is unaffected + self.assertEqual(stack.count, 6) + self.assertEqual(stack.names, names) + stack.close() + result.close() + + def test_drop_in_memory(self): + stack = Raster(self.predictors) + names = stack.names + + result = stack.intersect(in_memory=True) + result = stack.drop(labels="lsat7_2000_50", in_place=False) + + # check that Raster object is returned + self.assertIsInstance(result, Raster) + + # check that RasterLayer has been dropped + self.assertEqual(result.count, 5) + self.assertNotIn("lsat7_2000_50", result.names) + + # check that original raster is unaffected + self.assertEqual(stack.count, 6) + self.assertEqual(stack.names, names) + stack.close() diff --git a/tests/test_extract.py b/tests/test_extract.py index 80a35c2..8f77f35 100644 --- a/tests/test_extract.py +++ b/tests/test_extract.py @@ -1,130 +1,130 @@ -from copy import deepcopy -from unittest import TestCase - -import geopandas -import pandas as pd -import rasterio - -from pyspatialml import Raster -from pyspatialml.datasets import nc - - -class TestExtract(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.extracted_grass = pd.read_table(nc.extracted_pixels, delimiter=" ") - - self.stack = Raster(self.predictors) - - def tearDown(self) -> None: - self.stack.close() - - def test_extract_points(self): - training_pt = geopandas.read_file(nc.points) - - # check that extracted training data as a DataFrame match known values - df = self.stack.extract_vector(gdf=training_pt) - df = df.dropna() - training_pt = training_pt.dropna() - - self.assertTrue( - (df["lsat7_2000_10"].values == training_pt["b1"].values).all() - ) - self.assertTrue( - (df["lsat7_2000_20"].values == training_pt["b2"].values).all() - ) - self.assertTrue( - (df["lsat7_2000_30"].values == training_pt["b3"].values).all() - ) - self.assertTrue( - (df["lsat7_2000_40"].values == training_pt["b4"].values).all() - ) - self.assertTrue( - (df["lsat7_2000_50"].values == training_pt["b5"].values).all() - ) - self.assertTrue( - (df["lsat7_2000_70"].values == training_pt["b7"].values).all() - ) - - def test_extract_polygons(self): - # extract training data from polygons - training_py = geopandas.read_file(nc.polygons) - df = self.stack.extract_vector(gdf=training_py) - df = df.dropna() - - df = df.merge( - right=training_py.loc[:, ("id", "label")], - left_on="geometry_idx", - right_on="index", - right_index=True, - ) - - # compare to extracted data using GRASS GIS - self.assertEqual(df.shape[0], self.extracted_grass.shape[0]) - self.assertAlmostEqual( - df["lsat7_2000_10"].mean(), self.extracted_grass["b1"].mean(), - places=2 - ) - self.assertAlmostEqual( - df["lsat7_2000_20"].mean(), self.extracted_grass["b2"].mean(), - places=2 - ) - self.assertAlmostEqual( - df["lsat7_2000_30"].mean(), self.extracted_grass["b3"].mean(), - places=2 - ) - self.assertAlmostEqual( - df["lsat7_2000_40"].mean(), self.extracted_grass["b4"].mean(), - places=2 - ) - self.assertAlmostEqual( - df["lsat7_2000_50"].mean(), self.extracted_grass["b5"].mean(), - places=2 - ) - self.assertAlmostEqual( - df["lsat7_2000_70"].mean(), self.extracted_grass["b7"].mean(), - places=2 - ) - - def test_extract_lines(self): - # extract training data from lines - training_py = geopandas.read_file(nc.polygons) - training_lines = deepcopy(training_py) - training_lines["geometry"] = training_lines.geometry.boundary - df = self.stack.extract_vector(gdf=training_lines).dropna() - - # check shapes of extracted pixels - self.assertEqual(df.shape[0], 948) - - def test_extract_raster(self): - # extract training data from labelled pixels - with rasterio.open(nc.labelled_pixels) as src: - df = self.stack.extract_raster(src) - - df = df.dropna() - - self.assertEqual(df.shape[0], self.extracted_grass.shape[0]) - self.assertAlmostEqual( - df["lsat7_2000_10"].mean(), self.extracted_grass["b1"].mean(), - places=3 - ) - self.assertAlmostEqual( - df["lsat7_2000_20"].mean(), self.extracted_grass["b2"].mean(), - places=3 - ) - self.assertAlmostEqual( - df["lsat7_2000_30"].mean(), self.extracted_grass["b3"].mean(), - places=3 - ) - self.assertAlmostEqual( - df["lsat7_2000_40"].mean(), self.extracted_grass["b4"].mean(), - places=3 - ) - self.assertAlmostEqual( - df["lsat7_2000_50"].mean(), self.extracted_grass["b5"].mean(), - places=3 - ) - self.assertAlmostEqual( - df["lsat7_2000_70"].mean(), self.extracted_grass["b7"].mean(), - places=3 - ) +from copy import deepcopy +from unittest import TestCase + +import geopandas +import pandas as pd +import rasterio + +from pyspatialml import Raster +from pyspatialml.datasets import nc + + +class TestExtract(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.extracted_grass = pd.read_table(nc.extracted_pixels, delimiter=" ") + + self.stack = Raster(self.predictors) + + def tearDown(self) -> None: + self.stack.close() + + def test_extract_points(self): + training_pt = geopandas.read_file(nc.points) + + # check that extracted training data as a DataFrame match known values + df = self.stack.extract_vector(gdf=training_pt) + df = df.dropna() + training_pt = training_pt.dropna() + + self.assertTrue( + (df["lsat7_2000_10"].values == training_pt["b1"].values).all() + ) + self.assertTrue( + (df["lsat7_2000_20"].values == training_pt["b2"].values).all() + ) + self.assertTrue( + (df["lsat7_2000_30"].values == training_pt["b3"].values).all() + ) + self.assertTrue( + (df["lsat7_2000_40"].values == training_pt["b4"].values).all() + ) + self.assertTrue( + (df["lsat7_2000_50"].values == training_pt["b5"].values).all() + ) + self.assertTrue( + (df["lsat7_2000_70"].values == training_pt["b7"].values).all() + ) + + def test_extract_polygons(self): + # extract training data from polygons + training_py = geopandas.read_file(nc.polygons) + df = self.stack.extract_vector(gdf=training_py) + df = df.dropna() + + df = df.merge( + right=training_py.loc[:, ("id", "label")], + left_on="geometry_idx", + right_on="index", + right_index=True, + ) + + # compare to extracted data using GRASS GIS + self.assertEqual(df.shape[0], self.extracted_grass.shape[0]) + self.assertAlmostEqual( + df["lsat7_2000_10"].mean(), self.extracted_grass["b1"].mean(), + places=2 + ) + self.assertAlmostEqual( + df["lsat7_2000_20"].mean(), self.extracted_grass["b2"].mean(), + places=2 + ) + self.assertAlmostEqual( + df["lsat7_2000_30"].mean(), self.extracted_grass["b3"].mean(), + places=2 + ) + self.assertAlmostEqual( + df["lsat7_2000_40"].mean(), self.extracted_grass["b4"].mean(), + places=2 + ) + self.assertAlmostEqual( + df["lsat7_2000_50"].mean(), self.extracted_grass["b5"].mean(), + places=2 + ) + self.assertAlmostEqual( + df["lsat7_2000_70"].mean(), self.extracted_grass["b7"].mean(), + places=2 + ) + + def test_extract_lines(self): + # extract training data from lines + training_py = geopandas.read_file(nc.polygons) + training_lines = deepcopy(training_py) + training_lines["geometry"] = training_lines.geometry.boundary + df = self.stack.extract_vector(gdf=training_lines).dropna() + + # check shapes of extracted pixels + self.assertEqual(df.shape[0], 948) + + def test_extract_raster(self): + # extract training data from labelled pixels + with rasterio.open(nc.labelled_pixels) as src: + df = self.stack.extract_raster(src) + + df = df.dropna() + + self.assertEqual(df.shape[0], self.extracted_grass.shape[0]) + self.assertAlmostEqual( + df["lsat7_2000_10"].mean(), self.extracted_grass["b1"].mean(), + places=3 + ) + self.assertAlmostEqual( + df["lsat7_2000_20"].mean(), self.extracted_grass["b2"].mean(), + places=3 + ) + self.assertAlmostEqual( + df["lsat7_2000_30"].mean(), self.extracted_grass["b3"].mean(), + places=3 + ) + self.assertAlmostEqual( + df["lsat7_2000_40"].mean(), self.extracted_grass["b4"].mean(), + places=3 + ) + self.assertAlmostEqual( + df["lsat7_2000_50"].mean(), self.extracted_grass["b5"].mean(), + places=3 + ) + self.assertAlmostEqual( + df["lsat7_2000_70"].mean(), self.extracted_grass["b7"].mean(), + places=3 + ) diff --git a/tests/test_indexing.py b/tests/test_indexing.py index e9462c1..73a05d3 100644 --- a/tests/test_indexing.py +++ b/tests/test_indexing.py @@ -1,100 +1,100 @@ -from unittest import TestCase - -from pyspatialml import Raster, RasterLayer -from pyspatialml.datasets import nc - - -class TestIndexing(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - - def test_naming(self): - stack = Raster(self.predictors + [nc.multiband]) - - # check unique naming when stacking multiband raster - self.assertEqual(stack.count, 11) - expected_names = [ - "lsat7_2000_10", - "lsat7_2000_20", - "lsat7_2000_30", - "lsat7_2000_40", - "lsat7_2000_50", - "lsat7_2000_70", - "landsat_multiband_1", - "landsat_multiband_2", - "landsat_multiband_3", - "landsat_multiband_4", - "landsat_multiband_5", - ] - self.assertListEqual(list(stack.names), expected_names) - stack.close() - - def test_subset_single_layer(self): - stack = Raster(self.predictors + [nc.multiband]) - - # Subset a single layer using an index position - returns a RasterLayer - self.assertIsInstance(stack.iloc[0], RasterLayer) - - # Subset a single layer using a label - returns a RasterLayer - self.assertIsInstance(stack["lsat7_2000_10"], RasterLayer) - - # Subset a single layer using an attribute - returns a RasterLayer - self.assertIsInstance(stack.lsat7_2000_10, RasterLayer) - - # Check that the raster values are the same as the original values - # after subsetting - self.assertEqual( - stack.lsat7_2000_10.read(masked=True).mean(), - 80.56715262406088 - ) - self.assertEqual( - stack.lsat7_2000_70.read(masked=True).mean(), - 59.17773813401238 - ) - stack.close() - - def test_subset_multiple_layers(self): - stack = Raster(self.predictors + [nc.multiband]) - - # Subset multiple layers using a slice of index positions - # - returns a Raster object - self.assertIsInstance(stack.iloc[0:2], Raster) - - # Subset multiple layers using a list of index positions - # - returns a Raster object - self.assertIsInstance(stack.iloc[[0, 1, 2]], Raster) - - # Subset multiple layers using a list of labels - # - returns a Raster object - subset_raster = stack[["lsat7_2000_10", "lsat7_2000_70"]] - self.assertIsInstance(subset_raster, Raster) - self.assertListEqual( - list(subset_raster.names), - ["lsat7_2000_10", "lsat7_2000_70"] - ) - - # Check that label and integer subset return the same layers - self.assertListEqual( - list(stack.iloc[0:3].names), - list(stack[["lsat7_2000_10", "lsat7_2000_20", "lsat7_2000_30"]].names), - ) - - stack.close() - - def test_indexing(self): - stack = Raster(self.predictors + [nc.multiband]) - - # replace band 1 with band 7 - band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() - - stack.iloc[0] = Raster(nc.band7).iloc[0] - - self.assertEqual(stack.iloc[0].read(masked=True).mean(), band7_mean) - self.assertEqual(stack["lsat7_2000_10"].read(masked=True).mean(), - band7_mean) - self.assertEqual(stack["lsat7_2000_10"].read(masked=True).mean(), - band7_mean) - self.assertEqual(stack.lsat7_2000_10.read(masked=True).mean(), - band7_mean) - - stack.close() +from unittest import TestCase + +from pyspatialml import Raster, RasterLayer +from pyspatialml.datasets import nc + + +class TestIndexing(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + + def test_naming(self): + stack = Raster(self.predictors + [nc.multiband]) + + # check unique naming when stacking multiband raster + self.assertEqual(stack.count, 11) + expected_names = [ + "lsat7_2000_10", + "lsat7_2000_20", + "lsat7_2000_30", + "lsat7_2000_40", + "lsat7_2000_50", + "lsat7_2000_70", + "landsat_multiband_1", + "landsat_multiband_2", + "landsat_multiband_3", + "landsat_multiband_4", + "landsat_multiband_5", + ] + self.assertListEqual(list(stack.names), expected_names) + stack.close() + + def test_subset_single_layer(self): + stack = Raster(self.predictors + [nc.multiband]) + + # Subset a single layer using an index position - returns a RasterLayer + self.assertIsInstance(stack.iloc[0], RasterLayer) + + # Subset a single layer using a label - returns a RasterLayer + self.assertIsInstance(stack["lsat7_2000_10"], RasterLayer) + + # Subset a single layer using an attribute - returns a RasterLayer + self.assertIsInstance(stack.lsat7_2000_10, RasterLayer) + + # Check that the raster values are the same as the original values + # after subsetting + self.assertEqual( + stack.lsat7_2000_10.read(masked=True).mean(), + 80.56715262406088 + ) + self.assertEqual( + stack.lsat7_2000_70.read(masked=True).mean(), + 59.17773813401238 + ) + stack.close() + + def test_subset_multiple_layers(self): + stack = Raster(self.predictors + [nc.multiband]) + + # Subset multiple layers using a slice of index positions + # - returns a Raster object + self.assertIsInstance(stack.iloc[0:2], Raster) + + # Subset multiple layers using a list of index positions + # - returns a Raster object + self.assertIsInstance(stack.iloc[[0, 1, 2]], Raster) + + # Subset multiple layers using a list of labels + # - returns a Raster object + subset_raster = stack[["lsat7_2000_10", "lsat7_2000_70"]] + self.assertIsInstance(subset_raster, Raster) + self.assertListEqual( + list(subset_raster.names), + ["lsat7_2000_10", "lsat7_2000_70"] + ) + + # Check that label and integer subset return the same layers + self.assertListEqual( + list(stack.iloc[0:3].names), + list(stack[["lsat7_2000_10", "lsat7_2000_20", "lsat7_2000_30"]].names), + ) + + stack.close() + + def test_indexing(self): + stack = Raster(self.predictors + [nc.multiband]) + + # replace band 1 with band 7 + band7_mean = stack["lsat7_2000_70"].read(masked=True).mean() + + stack.iloc[0] = Raster(nc.band7).iloc[0] + + self.assertEqual(stack.iloc[0].read(masked=True).mean(), band7_mean) + self.assertEqual(stack["lsat7_2000_10"].read(masked=True).mean(), + band7_mean) + self.assertEqual(stack["lsat7_2000_10"].read(masked=True).mean(), + band7_mean) + self.assertEqual(stack.lsat7_2000_10.read(masked=True).mean(), + band7_mean) + + stack.close() diff --git a/tests/test_initiation.py b/tests/test_initiation.py index 41cc13d..3848d3f 100644 --- a/tests/test_initiation.py +++ b/tests/test_initiation.py @@ -1,108 +1,108 @@ -from unittest import TestCase - -import os -import rasterio -import numpy as np - -from pyspatialml import Raster, RasterLayer -from pyspatialml.datasets import nc - - -class TestInit(TestCase): - def setUp(self) -> None: - # inputs - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - - # test results - self.stack = None - - def tearDown(self) -> None: - self.stack.close() - - def test_initiation_files(self): - # test init from list of file paths - self.stack = Raster(self.predictors) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 6) - - def test_initiation_file(self): - # test init from single file path - self.stack = Raster(nc.band1) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 1) - - def test_initiation_datasetreader(self): - # test init from single rasterio.io.datasetreader - with rasterio.open(nc.band1) as src: - self.stack = Raster(src) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 1) - - def test_initiation_list_datasetreader(self): - # test init from list of rasterio.io.datasetreader objects - srcs = [] - for f in self.predictors: - srcs.append(rasterio.open(f)) - self.stack = Raster(srcs) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 6) - - def test_initiation_band(self): - # test init from single rasterio.band object - with rasterio.open(nc.band1) as src: - band = rasterio.band(src, 1) - self.stack = Raster(band) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 1) - - def test_initiation_list_bands(self): - # test init from list of rasterio.band objects - bands = [] - for f in self.predictors: - src = rasterio.open(f) - bands.append(rasterio.band(src, 1)) - self.stack = Raster(bands) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 6) - - def test_initiation_rasterlayer(self): - # test init from a single RasterLayer object - with rasterio.open(nc.band1) as src: - band = rasterio.band(src, 1) - layer = RasterLayer(band) - self.stack = Raster(layer) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 1) - - def test_initiation_list_rasterlayer(self): - # test init from a list of RasterLayer objects - layers = [] - for f in self.predictors: - src = rasterio.open(f) - band = rasterio.band(src, 1) - layers.append(RasterLayer(band)) - self.stack = Raster(layers) - self.assertIsInstance(self.stack, Raster) - self.assertEqual(self.stack.count, 6) - - def test_initiation_array(self): - # check initiation of single-band raster from file - arr = np.zeros((100, 100)) - self.stack = Raster(arr) - - # check output is written to tempfile - self.assertTrue(os.path.exists(self.stack.iloc[0].file)) - - # check some operations on the created raster - layer_name = list(self.stack.names)[0] - self.stack = self.stack.rename({layer_name: 'new_layer'}) - self.assertEqual(list(self.stack.names)[0], 'new_layer') - - # check initiation from array in memory - arr = np.zeros((100, 100)) - self.stack = Raster(arr, in_memory=True) - layer_name = list(self.stack.names)[0] - - self.stack = self.stack.rename({layer_name: 'new_layer'}) - self.assertEqual(list(self.stack.names)[0], 'new_layer') +from unittest import TestCase + +import os +import rasterio +import numpy as np + +from pyspatialml import Raster, RasterLayer +from pyspatialml.datasets import nc + + +class TestInit(TestCase): + def setUp(self) -> None: + # inputs + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + + # test results + self.stack = None + + def tearDown(self) -> None: + self.stack.close() + + def test_initiation_files(self): + # test init from list of file paths + self.stack = Raster(self.predictors) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 6) + + def test_initiation_file(self): + # test init from single file path + self.stack = Raster(nc.band1) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 1) + + def test_initiation_datasetreader(self): + # test init from single rasterio.io.datasetreader + with rasterio.open(nc.band1) as src: + self.stack = Raster(src) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 1) + + def test_initiation_list_datasetreader(self): + # test init from list of rasterio.io.datasetreader objects + srcs = [] + for f in self.predictors: + srcs.append(rasterio.open(f)) + self.stack = Raster(srcs) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 6) + + def test_initiation_band(self): + # test init from single rasterio.band object + with rasterio.open(nc.band1) as src: + band = rasterio.band(src, 1) + self.stack = Raster(band) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 1) + + def test_initiation_list_bands(self): + # test init from list of rasterio.band objects + bands = [] + for f in self.predictors: + src = rasterio.open(f) + bands.append(rasterio.band(src, 1)) + self.stack = Raster(bands) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 6) + + def test_initiation_rasterlayer(self): + # test init from a single RasterLayer object + with rasterio.open(nc.band1) as src: + band = rasterio.band(src, 1) + layer = RasterLayer(band) + self.stack = Raster(layer) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 1) + + def test_initiation_list_rasterlayer(self): + # test init from a list of RasterLayer objects + layers = [] + for f in self.predictors: + src = rasterio.open(f) + band = rasterio.band(src, 1) + layers.append(RasterLayer(band)) + self.stack = Raster(layers) + self.assertIsInstance(self.stack, Raster) + self.assertEqual(self.stack.count, 6) + + def test_initiation_array(self): + # check initiation of single-band raster from file + arr = np.zeros((100, 100)) + self.stack = Raster(arr) + + # check output is written to tempfile + self.assertTrue(os.path.exists(self.stack.iloc[0].file)) + + # check some operations on the created raster + layer_name = list(self.stack.names)[0] + self.stack = self.stack.rename({layer_name: 'new_layer'}) + self.assertEqual(list(self.stack.names)[0], 'new_layer') + + # check initiation from array in memory + arr = np.zeros((100, 100)) + self.stack = Raster(arr, in_memory=True) + layer_name = list(self.stack.names)[0] + + self.stack = self.stack.rename({layer_name: 'new_layer'}) + self.assertEqual(list(self.stack.names)[0], 'new_layer') diff --git a/tests/test_intersect.py b/tests/test_intersect.py index eb7a60d..13038bc 100644 --- a/tests/test_intersect.py +++ b/tests/test_intersect.py @@ -1,63 +1,63 @@ -from unittest import TestCase - -import numpy as np - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestIntersect(TestCase): - def setUp(self) -> None: - # inputs - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - self.stack = Raster(self.predictors) - - # test results - self.result = None - - def tearDown(self) -> None: - self.stack.close() - self.result.close() - - def test_intersect_defaults(self): - self.result = self.stack.intersect() - - # check raster object - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, self.stack.count) - self.assertEqual(self.result.read(masked=True).count(), 810552) - - # test nodata value is recognized - self.assertEqual(self.result.read(masked=True).min(), 1.0) - self.assertEqual(self.result.read(masked=True).max(), 255.0) - - def test_intersect_custom_dtype(self): - self.result = self.stack.intersect(dtype=np.int16) - - # check raster object - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, self.stack.count) - self.assertEqual(self.result.read(masked=True).count(), 810552) - - # test nodata value is recognized - self.assertEqual(self.result.read(masked=True).min(), 1) - self.assertEqual(self.result.read(masked=True).max(), 255) - - def test_intersect_custom_nodata(self): - self.result = self.stack.intersect(dtype=np.int16, nodata=-999) - - # check raster object - self.assertIsInstance(self.result, Raster) - self.assertEqual(self.result.count, self.stack.count) - self.assertEqual(self.result.read(masked=True).count(), 810552) - - # test nodata value is recognized - self.assertEqual(self.result.read(masked=True).min(), 1) - self.assertEqual(self.result.read(masked=True).max(), 255) - - def test_intersect_in_memory(self): - self.result = self.stack.intersect(in_memory=True) - - # check raster object - self.assertIsInstance(self.result, Raster) +from unittest import TestCase + +import numpy as np + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestIntersect(TestCase): + def setUp(self) -> None: + # inputs + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + self.stack = Raster(self.predictors) + + # test results + self.result = None + + def tearDown(self) -> None: + self.stack.close() + self.result.close() + + def test_intersect_defaults(self): + self.result = self.stack.intersect() + + # check raster object + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, self.stack.count) + self.assertEqual(self.result.read(masked=True).count(), 810552) + + # test nodata value is recognized + self.assertEqual(self.result.read(masked=True).min(), 1.0) + self.assertEqual(self.result.read(masked=True).max(), 255.0) + + def test_intersect_custom_dtype(self): + self.result = self.stack.intersect(dtype=np.int16) + + # check raster object + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, self.stack.count) + self.assertEqual(self.result.read(masked=True).count(), 810552) + + # test nodata value is recognized + self.assertEqual(self.result.read(masked=True).min(), 1) + self.assertEqual(self.result.read(masked=True).max(), 255) + + def test_intersect_custom_nodata(self): + self.result = self.stack.intersect(dtype=np.int16, nodata=-999) + + # check raster object + self.assertIsInstance(self.result, Raster) + self.assertEqual(self.result.count, self.stack.count) + self.assertEqual(self.result.read(masked=True).count(), 810552) + + # test nodata value is recognized + self.assertEqual(self.result.read(masked=True).min(), 1) + self.assertEqual(self.result.read(masked=True).max(), 255) + + def test_intersect_in_memory(self): + self.result = self.stack.intersect(in_memory=True) + + # check raster object + self.assertIsInstance(self.result, Raster) diff --git a/tests/test_mask.py b/tests/test_mask.py index d0770e3..b8e4c6b 100644 --- a/tests/test_mask.py +++ b/tests/test_mask.py @@ -1,79 +1,79 @@ -from unittest import TestCase - -import geopandas as gpd -import numpy as np - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestMask(TestCase): - def setUp(self) -> None: - # test inputs - training_py = gpd.read_file(nc.polygons) - self.mask_py = training_py.iloc[0:1, :] - - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - self.stack = Raster(predictors) - - # test results - self.masked_object = None - - def tearDown(self) -> None: - self.stack.close() - self.masked_object.close() - - def test_mask_defaults(self): - self.masked_object = self.stack.mask(self.mask_py) - - # check raster object - self.assertIsInstance(self.masked_object, Raster) - self.assertEqual(self.masked_object.count, self.stack.count) - self.assertEqual(self.masked_object.read(masked=True).count(), 738) - - # test nodata value is recognized - self.assertEqual(self.masked_object.read(masked=True).min(), 38.0) - self.assertEqual(self.masked_object.read(masked=True).max(), 168.0) - - def test_mask_inverted(self): - self.masked_object = self.stack.mask(self.mask_py, invert=True) - - # check raster object - self.assertIsInstance(self.masked_object, Raster) - self.assertEqual(self.masked_object.count, self.stack.count) - self.assertEqual(self.masked_object.read(masked=True).count(), 1051444) - - # test nodata value is recognized - self.assertEqual(self.masked_object.read(masked=True).min(), 1.0) - self.assertEqual(self.masked_object.read(masked=True).max(), 255.0) - - def test_mask_custom_dtype(self): - self.masked_object = self.stack.mask(self.mask_py, dtype=np.int16) - - # check raster object - self.assertIsInstance(self.masked_object, Raster) - self.assertEqual(self.masked_object.count, self.stack.count) - self.assertEqual(self.masked_object.read(masked=True).count(), 738) - - # test nodata value is recognized - self.assertEqual(self.masked_object.read(masked=True).min(), 38) - self.assertEqual(self.masked_object.read(masked=True).max(), 168) - - def test_mask_custom_nodata(self): - self.masked_object = self.stack.mask(self.mask_py, nodata=-99999) - - # check raster object - self.assertIsInstance(self.masked_object, Raster) - self.assertEqual(self.masked_object.count, self.stack.count) - self.assertEqual(self.masked_object.read(masked=True).count(), 738) - - # test nodata value is recognized - self.assertEqual(self.masked_object.read(masked=True).min(), 38.0) - self.assertEqual(self.masked_object.read(masked=True).max(), 168.0) - - def test_mask_in_memory(self): - self.masked_object = self.stack.mask(self.mask_py, in_memory=True) - - # check raster object - self.assertIsInstance(self.masked_object, Raster) +from unittest import TestCase + +import geopandas as gpd +import numpy as np + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestMask(TestCase): + def setUp(self) -> None: + # test inputs + training_py = gpd.read_file(nc.polygons) + self.mask_py = training_py.iloc[0:1, :] + + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + self.stack = Raster(predictors) + + # test results + self.masked_object = None + + def tearDown(self) -> None: + self.stack.close() + self.masked_object.close() + + def test_mask_defaults(self): + self.masked_object = self.stack.mask(self.mask_py) + + # check raster object + self.assertIsInstance(self.masked_object, Raster) + self.assertEqual(self.masked_object.count, self.stack.count) + self.assertEqual(self.masked_object.read(masked=True).count(), 738) + + # test nodata value is recognized + self.assertEqual(self.masked_object.read(masked=True).min(), 38.0) + self.assertEqual(self.masked_object.read(masked=True).max(), 168.0) + + def test_mask_inverted(self): + self.masked_object = self.stack.mask(self.mask_py, invert=True) + + # check raster object + self.assertIsInstance(self.masked_object, Raster) + self.assertEqual(self.masked_object.count, self.stack.count) + self.assertEqual(self.masked_object.read(masked=True).count(), 1051444) + + # test nodata value is recognized + self.assertEqual(self.masked_object.read(masked=True).min(), 1.0) + self.assertEqual(self.masked_object.read(masked=True).max(), 255.0) + + def test_mask_custom_dtype(self): + self.masked_object = self.stack.mask(self.mask_py, dtype=np.int16) + + # check raster object + self.assertIsInstance(self.masked_object, Raster) + self.assertEqual(self.masked_object.count, self.stack.count) + self.assertEqual(self.masked_object.read(masked=True).count(), 738) + + # test nodata value is recognized + self.assertEqual(self.masked_object.read(masked=True).min(), 38) + self.assertEqual(self.masked_object.read(masked=True).max(), 168) + + def test_mask_custom_nodata(self): + self.masked_object = self.stack.mask(self.mask_py, nodata=-99999) + + # check raster object + self.assertIsInstance(self.masked_object, Raster) + self.assertEqual(self.masked_object.count, self.stack.count) + self.assertEqual(self.masked_object.read(masked=True).count(), 738) + + # test nodata value is recognized + self.assertEqual(self.masked_object.read(masked=True).min(), 38.0) + self.assertEqual(self.masked_object.read(masked=True).max(), 168.0) + + def test_mask_in_memory(self): + self.masked_object = self.stack.mask(self.mask_py, in_memory=True) + + # check raster object + self.assertIsInstance(self.masked_object, Raster) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 93c9aa3..7f301f4 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,41 +1,41 @@ -from unittest import TestCase - -import matplotlib as mpl -import numpy as np - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestPlotting(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.stack = Raster(self.predictors) - self.stack_single = Raster(self.predictors[0]) - - def tearDown(self) -> None: - self.stack.close() - self.stack_single.close() - - def test_plotting_raster(self): - - # test basic raster matrix plot - p = self.stack.plot() - self.assertIsInstance(p, np.ndarray) - - # test with arguments - p = self.stack.plot( - cmap="plasma", - norm=mpl.colors.Normalize(vmin=10, vmax=100), - title_fontsize=10, - label_fontsize=10, - names=["band1", "band2", "band3", "band4", "band5", "band7"], - figsize=(10, 5), - legend_kwds={"orientation": "horizontal"} - ) - self.assertIsInstance(p, np.ndarray) - - def test_plotting_single(self): - p = self.stack_single.plot( - legend_kwds={"orientation": "horizontal", "fraction": 0.04}) - self.assertIsInstance(p, mpl.axes.Subplot) +from unittest import TestCase + +import matplotlib as mpl +import numpy as np + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestPlotting(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.stack = Raster(self.predictors) + self.stack_single = Raster(self.predictors[0]) + + def tearDown(self) -> None: + self.stack.close() + self.stack_single.close() + + def test_plotting_raster(self): + + # test basic raster matrix plot + p = self.stack.plot() + self.assertIsInstance(p, np.ndarray) + + # test with arguments + p = self.stack.plot( + cmap="plasma", + norm=mpl.colors.Normalize(vmin=10, vmax=100), + title_fontsize=10, + label_fontsize=10, + names=["band1", "band2", "band3", "band4", "band5", "band7"], + figsize=(10, 5), + legend_kwds={"orientation": "horizontal"} + ) + self.assertIsInstance(p, np.ndarray) + + def test_plotting_single(self): + p = self.stack_single.plot( + legend_kwds={"orientation": "horizontal", "fraction": 0.04}) + self.assertIsInstance(p, mpl.axes.Subplot) diff --git a/tests/test_prediction.py b/tests/test_prediction.py index d7d03ea..9c8bebf 100644 --- a/tests/test_prediction.py +++ b/tests/test_prediction.py @@ -1,215 +1,215 @@ -from unittest import TestCase - -import geopandas as gpd -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor - -import pyspatialml.datasets.meuse as ms -from pyspatialml import Raster -from pyspatialml.datasets import nc - - -class TestPrediction(TestCase): - nc_predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - stack_nc = Raster(nc_predictors) - stack_meuse = Raster(ms.predictors) - - def test_classification(self): - training_pt = gpd.read_file(nc.points) - df_points = self.stack_nc.extract_vector(gdf=training_pt) - df_points["class_id"] = training_pt["id"].values - df_points = df_points.dropna() - - clf = RandomForestClassifier(n_estimators=50) - X = df_points.drop(columns=["class_id", "geometry"]).values - y = df_points.class_id.values - clf.fit(X, y) - - # classification - cla = self.stack_nc.predict(estimator=clf, dtype="int16", nodata=0) - self.assertIsInstance(cla, Raster) - self.assertEqual(cla.count, 1) - self.assertEqual(cla.read(masked=True).count(), 135092) - - # class probabilities - probs = self.stack_nc.predict_proba(estimator=clf) - self.assertIsInstance(cla, Raster) - self.assertEqual(probs.count, 7) - - for layer in probs.values(): - self.assertEqual(layer.read(masked=True).count(), 135092) - - def test_classification_in_memory(self): - training_pt = gpd.read_file(nc.points) - df_points = self.stack_nc.extract_vector(gdf=training_pt) - df_points["class_id"] = training_pt["id"].values - df_points = df_points.dropna() - - clf = RandomForestClassifier(n_estimators=50) - X = df_points.drop(columns=["class_id", "geometry"]).values - y = df_points.class_id.values - clf.fit(X, y) - - # classification - cla = self.stack_nc.predict(estimator=clf, dtype="int16", nodata=0, - in_memory=True) - self.assertIsInstance(cla, Raster) - self.assertEqual(cla.count, 1) - self.assertEqual(cla.read(masked=True).count(), 135092) - cla.close() - - # class probabilities - probs = self.stack_nc.predict_proba(estimator=clf, in_memory=True) - self.assertIsInstance(cla, Raster) - self.assertEqual(probs.count, 7) - - for layer in probs.values(): - self.assertEqual(layer.read(masked=True).count(), 135092) - - probs.close() - - def test_regression(self): - training_pt = gpd.read_file(ms.meuse) - training = self.stack_meuse.extract_vector(gdf=training_pt) - training["zinc"] = training_pt["zinc"].values - training["cadmium"] = training_pt["cadmium"].values - training["copper"] = training_pt["copper"].values - training["lead"] = training_pt["lead"].values - training = training.dropna() - - # single target regression - regr = RandomForestRegressor(n_estimators=50) - X = training.loc[:, self.stack_meuse.names].values - y = training["zinc"].values - regr.fit(X, y) - - single_regr = self.stack_meuse.predict(regr) - self.assertIsInstance(single_regr, Raster) - self.assertEqual(single_regr.count, 1) - single_regr.close() - - # multi-target regression - y = training.loc[:, ["zinc", "cadmium", "copper", "lead"]] - regr.fit(X, y) - multi_regr = self.stack_meuse.predict(regr) - self.assertIsInstance(multi_regr, Raster) - self.assertEqual(multi_regr.count, 4) - multi_regr.close() - - def test_regression_in_memory(self): - training_pt = gpd.read_file(ms.meuse) - training = self.stack_meuse.extract_vector(gdf=training_pt) - training["zinc"] = training_pt["zinc"].values - training["cadmium"] = training_pt["cadmium"].values - training["copper"] = training_pt["copper"].values - training["lead"] = training_pt["lead"].values - training = training.dropna() - - # single target regression - regr = RandomForestRegressor(n_estimators=50) - X = training.loc[:, self.stack_meuse.names].values - y = training["zinc"].values - regr.fit(X, y) - - single_regr = self.stack_meuse.predict(regr, in_memory=True) - self.assertIsInstance(single_regr, Raster) - self.assertEqual(single_regr.count, 1) - single_regr.close() - - # multi-target regression - y = training.loc[:, ["zinc", "cadmium", "copper", "lead"]] - regr.fit(X, y) - multi_regr = self.stack_meuse.predict(regr, in_memory=True) - self.assertIsInstance(multi_regr, Raster) - self.assertEqual(multi_regr.count, 4) - multi_regr.close() - - def test_classification_with_single_constant(self): - training_pt = gpd.read_file(nc.points) - df_points = self.stack_nc.extract_vector(gdf=training_pt) - df_points["class_id"] = training_pt["id"].values - df_points = df_points.dropna() - - # classification with a single constant - df_points["constant"] = 1 - - clf = RandomForestClassifier(n_estimators=50) - X = df_points.drop(columns=["class_id", "geometry"]).values - y = df_points.class_id.values - clf.fit(X, y) - - cla = self.stack_nc.predict( - estimator=clf, - dtype="int16", - nodata=0, - constants=[1] - ) - self.assertIsInstance(cla, Raster) - self.assertEqual(cla.count, 1) - self.assertEqual(cla.read(masked=True).count(), 135092) - - probs = self.stack_nc.predict_proba(estimator=clf, constants=[1]) - self.assertIsInstance(cla, Raster) - self.assertEqual(probs.count, 7) - - for layer in probs.values(): - self.assertEqual(layer.read(masked=True).count(), 135092) - - def test_classification_with_list_constants(self): - training_pt = gpd.read_file(nc.points) - df_points = self.stack_nc.extract_vector(gdf=training_pt) - df_points["class_id"] = training_pt["id"].values - df_points = df_points.dropna() - - df_points["constant"] = 1 - df_points["constant2"] = 2 - - clf = RandomForestClassifier(n_estimators=50) - X = df_points.drop(columns=["class_id", "geometry"]).values - y = df_points.class_id.values - clf.fit(X, y) - - cla = self.stack_nc.predict( - estimator=clf, - dtype="int16", - nodata=0, - constants=[1, 2] - ) - self.assertIsInstance(cla, Raster) - self.assertEqual(cla.count, 1) - self.assertEqual(cla.read(masked=True).count(), 135092) - - probs = self.stack_nc.predict_proba(estimator=clf, constants=[1, 2]) - self.assertIsInstance(cla, Raster) - self.assertEqual(probs.count, 7) - - for layer in probs.values(): - self.assertEqual(layer.read(masked=True).count(), 135092) - - def test_classification_with_dict_constants(self): - # classification using constant to replace an existing layer - training_pt = gpd.read_file(nc.points) - df_points = self.stack_nc.extract_vector(gdf=training_pt) - df_points["class_id"] = training_pt["id"].values - df_points = df_points.dropna() - - clf = RandomForestClassifier(n_estimators=50) - X = df_points.drop(columns=["class_id", "geometry"]).values - y = df_points.class_id.values - clf.fit(X, y) - - cla = self.stack_nc.predict( - estimator=clf, - dtype="int16", - nodata=0, - constants={"lsat7_2000_10": 150} - ) - self.assertIsInstance(cla, Raster) - self.assertEqual(cla.count, 1) - self.assertEqual(cla.read(masked=True).count(), 135092) - - probs = self.stack_nc.predict_proba(estimator=clf, constants={"lsat7_2000_10": 150}) - self.assertIsInstance(cla, Raster) - self.assertEqual(probs.count, 7) - - for layer in probs.values(): - self.assertEqual(layer.read(masked=True).count(), 135092) +from unittest import TestCase + +import geopandas as gpd +from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor + +import pyspatialml.datasets.meuse as ms +from pyspatialml import Raster +from pyspatialml.datasets import nc + + +class TestPrediction(TestCase): + nc_predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + stack_nc = Raster(nc_predictors) + stack_meuse = Raster(ms.predictors) + + def test_classification(self): + training_pt = gpd.read_file(nc.points) + df_points = self.stack_nc.extract_vector(gdf=training_pt) + df_points["class_id"] = training_pt["id"].values + df_points = df_points.dropna() + + clf = RandomForestClassifier(n_estimators=50) + X = df_points.drop(columns=["class_id", "geometry"]).values + y = df_points.class_id.values + clf.fit(X, y) + + # classification + cla = self.stack_nc.predict(estimator=clf, dtype="int16", nodata=0) + self.assertIsInstance(cla, Raster) + self.assertEqual(cla.count, 1) + self.assertEqual(cla.read(masked=True).count(), 135092) + + # class probabilities + probs = self.stack_nc.predict_proba(estimator=clf) + self.assertIsInstance(cla, Raster) + self.assertEqual(probs.count, 7) + + for layer in probs.values(): + self.assertEqual(layer.read(masked=True).count(), 135092) + + def test_classification_in_memory(self): + training_pt = gpd.read_file(nc.points) + df_points = self.stack_nc.extract_vector(gdf=training_pt) + df_points["class_id"] = training_pt["id"].values + df_points = df_points.dropna() + + clf = RandomForestClassifier(n_estimators=50) + X = df_points.drop(columns=["class_id", "geometry"]).values + y = df_points.class_id.values + clf.fit(X, y) + + # classification + cla = self.stack_nc.predict(estimator=clf, dtype="int16", nodata=0, + in_memory=True) + self.assertIsInstance(cla, Raster) + self.assertEqual(cla.count, 1) + self.assertEqual(cla.read(masked=True).count(), 135092) + cla.close() + + # class probabilities + probs = self.stack_nc.predict_proba(estimator=clf, in_memory=True) + self.assertIsInstance(cla, Raster) + self.assertEqual(probs.count, 7) + + for layer in probs.values(): + self.assertEqual(layer.read(masked=True).count(), 135092) + + probs.close() + + def test_regression(self): + training_pt = gpd.read_file(ms.meuse) + training = self.stack_meuse.extract_vector(gdf=training_pt) + training["zinc"] = training_pt["zinc"].values + training["cadmium"] = training_pt["cadmium"].values + training["copper"] = training_pt["copper"].values + training["lead"] = training_pt["lead"].values + training = training.dropna() + + # single target regression + regr = RandomForestRegressor(n_estimators=50) + X = training.loc[:, self.stack_meuse.names].values + y = training["zinc"].values + regr.fit(X, y) + + single_regr = self.stack_meuse.predict(regr) + self.assertIsInstance(single_regr, Raster) + self.assertEqual(single_regr.count, 1) + single_regr.close() + + # multi-target regression + y = training.loc[:, ["zinc", "cadmium", "copper", "lead"]] + regr.fit(X, y) + multi_regr = self.stack_meuse.predict(regr) + self.assertIsInstance(multi_regr, Raster) + self.assertEqual(multi_regr.count, 4) + multi_regr.close() + + def test_regression_in_memory(self): + training_pt = gpd.read_file(ms.meuse) + training = self.stack_meuse.extract_vector(gdf=training_pt) + training["zinc"] = training_pt["zinc"].values + training["cadmium"] = training_pt["cadmium"].values + training["copper"] = training_pt["copper"].values + training["lead"] = training_pt["lead"].values + training = training.dropna() + + # single target regression + regr = RandomForestRegressor(n_estimators=50) + X = training.loc[:, self.stack_meuse.names].values + y = training["zinc"].values + regr.fit(X, y) + + single_regr = self.stack_meuse.predict(regr, in_memory=True) + self.assertIsInstance(single_regr, Raster) + self.assertEqual(single_regr.count, 1) + single_regr.close() + + # multi-target regression + y = training.loc[:, ["zinc", "cadmium", "copper", "lead"]] + regr.fit(X, y) + multi_regr = self.stack_meuse.predict(regr, in_memory=True) + self.assertIsInstance(multi_regr, Raster) + self.assertEqual(multi_regr.count, 4) + multi_regr.close() + + def test_classification_with_single_constant(self): + training_pt = gpd.read_file(nc.points) + df_points = self.stack_nc.extract_vector(gdf=training_pt) + df_points["class_id"] = training_pt["id"].values + df_points = df_points.dropna() + + # classification with a single constant + df_points["constant"] = 1 + + clf = RandomForestClassifier(n_estimators=50) + X = df_points.drop(columns=["class_id", "geometry"]).values + y = df_points.class_id.values + clf.fit(X, y) + + cla = self.stack_nc.predict( + estimator=clf, + dtype="int16", + nodata=0, + constants=[1] + ) + self.assertIsInstance(cla, Raster) + self.assertEqual(cla.count, 1) + self.assertEqual(cla.read(masked=True).count(), 135092) + + probs = self.stack_nc.predict_proba(estimator=clf, constants=[1]) + self.assertIsInstance(cla, Raster) + self.assertEqual(probs.count, 7) + + for layer in probs.values(): + self.assertEqual(layer.read(masked=True).count(), 135092) + + def test_classification_with_list_constants(self): + training_pt = gpd.read_file(nc.points) + df_points = self.stack_nc.extract_vector(gdf=training_pt) + df_points["class_id"] = training_pt["id"].values + df_points = df_points.dropna() + + df_points["constant"] = 1 + df_points["constant2"] = 2 + + clf = RandomForestClassifier(n_estimators=50) + X = df_points.drop(columns=["class_id", "geometry"]).values + y = df_points.class_id.values + clf.fit(X, y) + + cla = self.stack_nc.predict( + estimator=clf, + dtype="int16", + nodata=0, + constants=[1, 2] + ) + self.assertIsInstance(cla, Raster) + self.assertEqual(cla.count, 1) + self.assertEqual(cla.read(masked=True).count(), 135092) + + probs = self.stack_nc.predict_proba(estimator=clf, constants=[1, 2]) + self.assertIsInstance(cla, Raster) + self.assertEqual(probs.count, 7) + + for layer in probs.values(): + self.assertEqual(layer.read(masked=True).count(), 135092) + + def test_classification_with_dict_constants(self): + # classification using constant to replace an existing layer + training_pt = gpd.read_file(nc.points) + df_points = self.stack_nc.extract_vector(gdf=training_pt) + df_points["class_id"] = training_pt["id"].values + df_points = df_points.dropna() + + clf = RandomForestClassifier(n_estimators=50) + X = df_points.drop(columns=["class_id", "geometry"]).values + y = df_points.class_id.values + clf.fit(X, y) + + cla = self.stack_nc.predict( + estimator=clf, + dtype="int16", + nodata=0, + constants={"lsat7_2000_10": 150} + ) + self.assertIsInstance(cla, Raster) + self.assertEqual(cla.count, 1) + self.assertEqual(cla.read(masked=True).count(), 135092) + + probs = self.stack_nc.predict_proba(estimator=clf, constants={"lsat7_2000_10": 150}) + self.assertIsInstance(cla, Raster) + self.assertEqual(probs.count, 7) + + for layer in probs.values(): + self.assertEqual(layer.read(masked=True).count(), 135092) diff --git a/tests/test_rename.py b/tests/test_rename.py index fdd8072..70d3b17 100644 --- a/tests/test_rename.py +++ b/tests/test_rename.py @@ -1,106 +1,106 @@ -from unittest import TestCase - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster -import rasterio -import numpy as np -import os -from tempfile import NamedTemporaryFile - - -class TestRename(TestCase): - def setUp(self) -> None: - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - - def test_rename_inplace(self): - stack = Raster(self.predictors) - band3_stats = stack.lsat7_2000_30.mean() - - # rename band 3 - stack.rename(names={"lsat7_2000_30": "new_name"}, in_place=True) - - # check that renaming occurred in Raster - self.assertEqual(list(stack.names)[2], "new_name") - self.assertNotIn("lsat7_2000_30", stack.names) - - # check that Raster layer properties also renamed - self.assertIn("new_name", dir(stack)) - self.assertNotIn("lsat7_2000_30", dir(stack)) - - # check that internal name of RasterLayer was also renamed - self.assertEqual(stack.iloc[2].name, "new_name") - - # check that the RasterLayer attached to the new name is the same - self.assertEqual(stack["new_name"].mean(), band3_stats) - self.assertEqual(stack.new_name.mean(), band3_stats) - self.assertEqual(stack.iloc[2].mean(), band3_stats) - - # check that a new Raster object derived from the renamed data - # have the right names - new_raster = Raster(src=stack.iloc[2]) - self.assertIn("new_name", new_raster.names) - - def test_rename_with_copy(self): - stack = Raster(self.predictors) - names = list(stack.names) - band3_stats = stack.lsat7_2000_30.mean() - - # rename band 3 - result = stack.rename(names={"lsat7_2000_30": "new_name"}, - in_place=False) - - # check that original is untouched - self.assertEqual(list(stack.names), names) - - # check that renaming occurred in Raster - self.assertEqual(list(result.names)[2], "new_name") - self.assertNotIn("lsat7_2000_30", result.names) - - # check that Raster layer properties also renamed - self.assertIn("new_name", dir(result)) - self.assertNotIn("lsat7_2000_30", dir(result)) - - # check that internal name of RasterLayer was also renamed - self.assertEqual(result.iloc[2].name, "new_name") - - # check that the RasterLayer attached to the new name is the same - self.assertEqual(result["new_name"].mean(), band3_stats) - self.assertEqual(result["new_name"].mean(), band3_stats) - self.assertEqual(result.new_name.mean(), band3_stats) - self.assertEqual(result.iloc[2].mean(), band3_stats) - - # check that a new Raster object derived from the renamed data - # have the right names - new_raster = Raster(src=result.iloc[2]) - self.assertIn("new_name", new_raster.names) - - def rename_multiband(self): - # Create a fake 3-band image for testing - arr = np.random.rand(3, 64, 64) - file = NamedTemporaryFile(prefix="test", suffix=".tif").name - layer_name = os.path.basename(file).split(".")[0] - layer_names = ["_".join([layer_name, str(i)]) for i in [1, 2 ,3]] - - with rasterio.open(file, "w", width=64, height=64, count=3, dtype=np.float32) as dst: - dst.write(arr) - - r = Raster(file) - self.assertListEqual(list(r.names), layer_names) - - renamed = r.rename(dict(zip(r.names, ["Red", "Green", "Blue"]))) - self.assertListEqual(list(renamed.names), ["Red", "Green", "Blue"]) - - def rename_in_memory(self): - # Create a fake 3-band image for testing - arr = np.random.rand(3, 64, 64) - file = NamedTemporaryFile(prefix="test", suffix=".tif").name - - with rasterio.open(file, "w", width=64, height=64, count=3, dtype=np.float32) as dst: - dst.write(arr) - - r = Raster(file) - in_memory = r.aggregate((32, 32), in_memory=True) - - renamed = r.rename(dict(zip(in_memory.names, ["Red", "Green", "Blue"]))) - self.assertListEqual(list(renamed.names), ["Red", "Green", "Blue"]) +from unittest import TestCase + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster +import rasterio +import numpy as np +import os +from tempfile import NamedTemporaryFile + + +class TestRename(TestCase): + def setUp(self) -> None: + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + + def test_rename_inplace(self): + stack = Raster(self.predictors) + band3_stats = stack.lsat7_2000_30.mean() + + # rename band 3 + stack.rename(names={"lsat7_2000_30": "new_name"}, in_place=True) + + # check that renaming occurred in Raster + self.assertEqual(list(stack.names)[2], "new_name") + self.assertNotIn("lsat7_2000_30", stack.names) + + # check that Raster layer properties also renamed + self.assertIn("new_name", dir(stack)) + self.assertNotIn("lsat7_2000_30", dir(stack)) + + # check that internal name of RasterLayer was also renamed + self.assertEqual(stack.iloc[2].name, "new_name") + + # check that the RasterLayer attached to the new name is the same + self.assertEqual(stack["new_name"].mean(), band3_stats) + self.assertEqual(stack.new_name.mean(), band3_stats) + self.assertEqual(stack.iloc[2].mean(), band3_stats) + + # check that a new Raster object derived from the renamed data + # have the right names + new_raster = Raster(src=stack.iloc[2]) + self.assertIn("new_name", new_raster.names) + + def test_rename_with_copy(self): + stack = Raster(self.predictors) + names = list(stack.names) + band3_stats = stack.lsat7_2000_30.mean() + + # rename band 3 + result = stack.rename(names={"lsat7_2000_30": "new_name"}, + in_place=False) + + # check that original is untouched + self.assertEqual(list(stack.names), names) + + # check that renaming occurred in Raster + self.assertEqual(list(result.names)[2], "new_name") + self.assertNotIn("lsat7_2000_30", result.names) + + # check that Raster layer properties also renamed + self.assertIn("new_name", dir(result)) + self.assertNotIn("lsat7_2000_30", dir(result)) + + # check that internal name of RasterLayer was also renamed + self.assertEqual(result.iloc[2].name, "new_name") + + # check that the RasterLayer attached to the new name is the same + self.assertEqual(result["new_name"].mean(), band3_stats) + self.assertEqual(result["new_name"].mean(), band3_stats) + self.assertEqual(result.new_name.mean(), band3_stats) + self.assertEqual(result.iloc[2].mean(), band3_stats) + + # check that a new Raster object derived from the renamed data + # have the right names + new_raster = Raster(src=result.iloc[2]) + self.assertIn("new_name", new_raster.names) + + def rename_multiband(self): + # Create a fake 3-band image for testing + arr = np.random.rand(3, 64, 64) + file = NamedTemporaryFile(prefix="test", suffix=".tif").name + layer_name = os.path.basename(file).split(".")[0] + layer_names = ["_".join([layer_name, str(i)]) for i in [1, 2 ,3]] + + with rasterio.open(file, "w", width=64, height=64, count=3, dtype=np.float32) as dst: + dst.write(arr) + + r = Raster(file) + self.assertListEqual(list(r.names), layer_names) + + renamed = r.rename(dict(zip(r.names, ["Red", "Green", "Blue"]))) + self.assertListEqual(list(renamed.names), ["Red", "Green", "Blue"]) + + def rename_in_memory(self): + # Create a fake 3-band image for testing + arr = np.random.rand(3, 64, 64) + file = NamedTemporaryFile(prefix="test", suffix=".tif").name + + with rasterio.open(file, "w", width=64, height=64, count=3, dtype=np.float32) as dst: + dst.write(arr) + + r = Raster(file) + in_memory = r.aggregate((32, 32), in_memory=True) + + renamed = r.rename(dict(zip(in_memory.names, ["Red", "Green", "Blue"]))) + self.assertListEqual(list(renamed.names), ["Red", "Green", "Blue"]) diff --git a/tests/test_sample.py b/tests/test_sample.py index 713d5fa..d725361 100644 --- a/tests/test_sample.py +++ b/tests/test_sample.py @@ -1,42 +1,42 @@ -from unittest import TestCase - -import numpy as np - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestSample(TestCase): - def setUp(self) -> None: - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.stack = Raster(predictors) - self.strata = Raster(nc.strata) - - def tearDown(self) -> None: - self.stack.close() - self.strata.close() - - def test_sample_strata(self): - # extract using a strata raster and returning two arrays - size = 100 - categories = self.strata.read(masked=True).flatten() - categories = categories[~categories.mask] - n_categories = np.unique(categories).shape[0] - n_samples = size * n_categories - - X, xy = self.stack.sample(size=size, strata=self.strata, return_array=True) - self.assertEqual(X.shape, (n_samples, 6)) - self.assertEqual(xy.shape, (n_samples, 2)) - - # extract using a strata raster and returning a dataframe - samples = self.stack.sample(size=size, strata=self.strata, return_array=False) - self.assertEqual(samples.shape, (n_samples, 7)) - - def test_sample_no_strata(self): - size = 100 - X, xy = self.stack.sample(size=size, return_array=True) - self.assertEqual(X.shape, (size, 6)) - self.assertEqual(xy.shape, (size, 2)) - - samples = self.stack.sample(size=size, return_array=False) +from unittest import TestCase + +import numpy as np + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestSample(TestCase): + def setUp(self) -> None: + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.stack = Raster(predictors) + self.strata = Raster(nc.strata) + + def tearDown(self) -> None: + self.stack.close() + self.strata.close() + + def test_sample_strata(self): + # extract using a strata raster and returning two arrays + size = 100 + categories = self.strata.read(masked=True).flatten() + categories = categories[~categories.mask] + n_categories = np.unique(categories).shape[0] + n_samples = size * n_categories + + X, xy = self.stack.sample(size=size, strata=self.strata, return_array=True) + self.assertEqual(X.shape, (n_samples, 6)) + self.assertEqual(xy.shape, (n_samples, 2)) + + # extract using a strata raster and returning a dataframe + samples = self.stack.sample(size=size, strata=self.strata, return_array=False) + self.assertEqual(samples.shape, (n_samples, 7)) + + def test_sample_no_strata(self): + size = 100 + X, xy = self.stack.sample(size=size, return_array=True) + self.assertEqual(X.shape, (size, 6)) + self.assertEqual(xy.shape, (size, 2)) + + samples = self.stack.sample(size=size, return_array=False) self.assertEqual(samples.shape, (size, 7)) \ No newline at end of file diff --git a/tests/test_stats.py b/tests/test_stats.py index ce86a6f..6de9f74 100644 --- a/tests/test_stats.py +++ b/tests/test_stats.py @@ -1,33 +1,33 @@ -import numpy as np -import unittest -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestStats(unittest.TestCase): - def setUp(self) -> None: - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] - self.predictors = predictors - self.stack = Raster(predictors) - - def test_rasterstats(self): - self.assertEqual(len(self.stack.min()), len(self.predictors)) - self.assertTrue(~np.isnan(self.stack.min()).all()) - - self.assertEqual(len(self.stack.max()), len(self.predictors)) - self.assertTrue(~np.isnan(self.stack.max()).all()) - - self.assertEqual(len(self.stack.mean()), len(self.predictors)) - self.assertTrue(~np.isnan(self.stack.mean()).all()) - - self.assertEqual(len(self.stack.median()), len(self.predictors)) - self.assertTrue(~np.isnan(self.stack.median()).all()) - - def test_layerstats(self): - self.assertEqual(self.stack.iloc[0].min(), 56.0) - self.assertEqual(self.stack.iloc[0].max(), 255.0) - self.assertAlmostEqual(self.stack.iloc[0].mean(), 80.6, places=0) - self.assertEqual(self.stack.iloc[0].median(), 75.0) - -if __name__ == '__main__': - unittest.main() +import numpy as np +import unittest +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestStats(unittest.TestCase): + def setUp(self) -> None: + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7] + self.predictors = predictors + self.stack = Raster(predictors) + + def test_rasterstats(self): + self.assertEqual(len(self.stack.min()), len(self.predictors)) + self.assertTrue(~np.isnan(self.stack.min()).all()) + + self.assertEqual(len(self.stack.max()), len(self.predictors)) + self.assertTrue(~np.isnan(self.stack.max()).all()) + + self.assertEqual(len(self.stack.mean()), len(self.predictors)) + self.assertTrue(~np.isnan(self.stack.mean()).all()) + + self.assertEqual(len(self.stack.median()), len(self.predictors)) + self.assertTrue(~np.isnan(self.stack.median()).all()) + + def test_layerstats(self): + self.assertEqual(self.stack.iloc[0].min(), 56.0) + self.assertEqual(self.stack.iloc[0].max(), 255.0) + self.assertAlmostEqual(self.stack.iloc[0].mean(), 80.6, places=0) + self.assertEqual(self.stack.iloc[0].median(), 75.0) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_tocrs.py b/tests/test_tocrs.py index 3a4b5b0..1f31314 100644 --- a/tests/test_tocrs.py +++ b/tests/test_tocrs.py @@ -1,62 +1,62 @@ -from unittest import TestCase - -import pyspatialml.datasets.nc as nc -from pyspatialml import Raster - - -class TestToCrs(TestCase): - def setUp(self) -> None: - # test inputs - predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - self.stack = Raster(predictors) - - # test results - self.stack_prj = None - - def tearDown(self) -> None: - self.stack.close() - self.stack_prj.close() - - def test_to_crs_defaults(self): - self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}) - - # check raster object - self.assertIsInstance(self.stack_prj, Raster) - self.assertEqual(self.stack_prj.count, self.stack.count) - self.assertEqual(self.stack_prj.read(masked=True).count(), 1012061) - - # test nodata value is recognized - self.assertEqual( - self.stack_prj.read(masked=True).min(), - self.stack.read(masked=True).min() - ) - self.assertEqual( - self.stack_prj.read(masked=True).max(), - self.stack.read(masked=True).max() - ) - - def test_to_crs_custom_nodata(self): - self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}, nodata=-999) - - # check raster object - self.assertIsInstance(self.stack_prj, Raster) - self.assertEqual(self.stack_prj.count, self.stack.count) - self.assertEqual(self.stack_prj.read(masked=True).count(), 1012061) - - # test nodata value is recognized - self.assertEqual( - self.stack_prj.read(masked=True).min(), - self.stack.read(masked=True).min() - ) - self.assertEqual( - self.stack_prj.read(masked=True).max(), - self.stack.read(masked=True).max() - ) - - def test_to_crs_in_memory(self): - self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}, - in_memory=True) - - # check raster object - self.assertIsInstance(self.stack_prj, Raster) +from unittest import TestCase + +import pyspatialml.datasets.nc as nc +from pyspatialml import Raster + + +class TestToCrs(TestCase): + def setUp(self) -> None: + # test inputs + predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + self.stack = Raster(predictors) + + # test results + self.stack_prj = None + + def tearDown(self) -> None: + self.stack.close() + self.stack_prj.close() + + def test_to_crs_defaults(self): + self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}) + + # check raster object + self.assertIsInstance(self.stack_prj, Raster) + self.assertEqual(self.stack_prj.count, self.stack.count) + self.assertEqual(self.stack_prj.read(masked=True).count(), 1012061) + + # test nodata value is recognized + self.assertEqual( + self.stack_prj.read(masked=True).min(), + self.stack.read(masked=True).min() + ) + self.assertEqual( + self.stack_prj.read(masked=True).max(), + self.stack.read(masked=True).max() + ) + + def test_to_crs_custom_nodata(self): + self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}, nodata=-999) + + # check raster object + self.assertIsInstance(self.stack_prj, Raster) + self.assertEqual(self.stack_prj.count, self.stack.count) + self.assertEqual(self.stack_prj.read(masked=True).count(), 1012061) + + # test nodata value is recognized + self.assertEqual( + self.stack_prj.read(masked=True).min(), + self.stack.read(masked=True).min() + ) + self.assertEqual( + self.stack_prj.read(masked=True).max(), + self.stack.read(masked=True).max() + ) + + def test_to_crs_in_memory(self): + self.stack_prj = self.stack.to_crs({"init": "EPSG:4326"}, + in_memory=True) + + # check raster object + self.assertIsInstance(self.stack_prj, Raster) diff --git a/tests/test_transformers.py b/tests/test_transformers.py index 7c6c250..4e31c39 100644 --- a/tests/test_transformers.py +++ b/tests/test_transformers.py @@ -1,15 +1,15 @@ -from unittest import TestCase -from pyspatialml.transformers import AspectTransformer - -import numpy as np - -class TestTransformers(TestCase): - def test_aspect_transformer(self): - trans = AspectTransformer() - dirs = np.arange(0, 360, 1, dtype=np.float32) - - mag = trans.fit_transform(dirs) - inverse = trans.inverse_transform(mag) - inverse = inverse.round(0) - - self.assertListEqual(dirs.tolist(), inverse.tolist()) +from unittest import TestCase +from pyspatialml.transformers import AspectTransformer + +import numpy as np + +class TestTransformers(TestCase): + def test_aspect_transformer(self): + trans = AspectTransformer() + dirs = np.arange(0, 360, 1, dtype=np.float32) + + mag = trans.fit_transform(dirs) + inverse = trans.inverse_transform(mag) + inverse = inverse.round(0) + + self.assertListEqual(dirs.tolist(), inverse.tolist()) diff --git a/tests/test_write.py b/tests/test_write.py index 1c7a8ed..d745ac7 100644 --- a/tests/test_write.py +++ b/tests/test_write.py @@ -1,28 +1,28 @@ -from unittest import TestCase -from tempfile import NamedTemporaryFile - -from pyspatialml import Raster -from pyspatialml.datasets import nc - - -class TestWrite(TestCase): - def setUp(self) -> None: - # inputs - self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, - nc.band7] - - # test results - self.stack = None - - def tearDown(self) -> None: - self.stack.close() - - def test_write(self): - # test writing to file - self.stack = Raster(self.predictors) - fp = NamedTemporaryFile(suffix=".tif").name - - result = self.stack.write(fp) - - self.assertIsInstance(result, Raster) - self.assertEqual(result.count, self.stack.count) +from unittest import TestCase +from tempfile import NamedTemporaryFile + +from pyspatialml import Raster +from pyspatialml.datasets import nc + + +class TestWrite(TestCase): + def setUp(self) -> None: + # inputs + self.predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, + nc.band7] + + # test results + self.stack = None + + def tearDown(self) -> None: + self.stack.close() + + def test_write(self): + # test writing to file + self.stack = Raster(self.predictors) + fp = NamedTemporaryFile(suffix=".tif").name + + result = self.stack.write(fp) + + self.assertIsInstance(result, Raster) + self.assertEqual(result.count, self.stack.count)