From ed7aa0505dbd9391b78f92a447bb8115ca876cc4 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 09:43:06 +0200 Subject: [PATCH 1/8] Create initial version of logki --- .github/workflows/actions/setup/action.yml | 30 ++ .github/workflows/release.yml | 86 +++++ .github/workflows/ubuntu.yml | 111 ++++++ AUTHORS.rst | 12 + CHANGELOG.rst | 7 + CONTRIBUTING.rst | 36 ++ Makefile | 42 +++ README.md | 104 +++++- examples/example.log | 222 +++++++++++ figs/logo.jpg | Bin 0 -> 148160 bytes logki/logki.py | 415 +++++++++++++++++++++ pyproject.toml | 111 ++++++ tests/test_logki.py | 23 ++ tests/workloads/example.log | 222 +++++++++++ tox.ini | 41 ++ 15 files changed, 1460 insertions(+), 2 deletions(-) create mode 100755 .github/workflows/actions/setup/action.yml create mode 100755 .github/workflows/release.yml create mode 100755 .github/workflows/ubuntu.yml create mode 100755 AUTHORS.rst create mode 100755 CHANGELOG.rst create mode 100755 CONTRIBUTING.rst create mode 100755 Makefile mode change 100644 => 100755 README.md create mode 100755 examples/example.log create mode 100755 figs/logo.jpg create mode 100755 logki/logki.py create mode 100755 pyproject.toml create mode 100755 tests/test_logki.py create mode 100755 tests/workloads/example.log create mode 100755 tox.ini diff --git a/.github/workflows/actions/setup/action.yml b/.github/workflows/actions/setup/action.yml new file mode 100755 index 0000000..9373e0f --- /dev/null +++ b/.github/workflows/actions/setup/action.yml @@ -0,0 +1,30 @@ +name: Setup Environment +description: Performs setup of Python and its dependencies +inputs: + python-version: + description: 'Python version to run' + required: true + +runs: + using: 'composite' + steps: + - name: Set up Python ${{ inputs.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ inputs.python-version }} + cache: 'pip' + + - name: Install Unix dependencies + shell: sh + run: | + sudo apt-get -qq update + + - name: Upgrade pip and build dependencies + shell: sh + run: | + python -m pip install --upgrade pip setuptools + + - name: Install Tox + shell: sh + run: | + pip install tox diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100755 index 0000000..d345dd3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Release + +on: + pull_request: + types: + - closed + branches: + - devel + +jobs: + release: + if: ${{ github.event.pull_request.merged == true && contains(github.head_ref, 'release') }} + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + steps: + - name: Checkout latest version + uses: actions/checkout@v3 + with: + ref: devel + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Install logki(to assure it is correctly installed) and try obtaining the version + run: | + make install + logki --version + + - name: Set version + id: manual-tagger + run: echo "NEW_TAG=$(logki --version | cut -d' ' -f2)" >> "$GITHUB_OUTPUT" + + - name: Tag the new version + uses: rickstaa/action-create-tag@v1.7.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ steps.manual-tagger.outputs.NEW_TAG }} + + build-and-deploy-to-pypi: + needs: release + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - name: Checkout latest version + uses: actions/checkout@v3 + with: + ref: devel + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Ensure that dependencies are installed + run: | + # Install and upgrade pip + python3 -m pip install --upgrade pip + # Install dependencies for build and deploy + python3 -m pip install build wheel twine + + - name: Build python release distribution package + run: | + make release + + - name: Upload to TestPypi + run: | + python3 -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.TESTPYPI_SECRET_TOKEN }} + TWINE_REPOSITORY: testpypi + + - name: Upload to Pypi + run: | + python3 -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_SECRET_TOKEN }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml new file mode 100755 index 0000000..9f110b1 --- /dev/null +++ b/.github/workflows/ubuntu.yml @@ -0,0 +1,111 @@ +name: Ubuntu (build-&-test) + +on: + push: + branches: + - devel + pull_request: + branches: + - devel + +jobs: + # Tests classic build using Tox for selected Python versions + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Execute tests for Python ${{ matrix.python-version }} using Tox + run: tox -e py + + - name: Generate docs for Python ${{ matrix.python-version }} using Tox + run: | + tox -e docs + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + flags: coverage-${{ matrix.python-version }} + verbose: true + + # Tests that logki is buildable from distribution packages (this is precursor for pypi install). + # We limit the test to version 3.11 in order to have less clutter in Actions + build-from-dist: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Create tarball or wheel + run: | + pip3 install -q build + make release + + - name: Install from dist (wheel) + run: | + pip3 install dist/*.whl + + - name: Install from dist (tar.gz) + run: | + pip3 install dist/*.tar.gz + + - name: Try running logki and getting help + run: | + logki --version + + # Tests correctes of typing for all versions + typing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Check type correctness for Python ${{ matrix.python-version }} using Tox + run: | + tox -e typing + + # Test linting only for the latest version of python + linting: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python, Ubuntu and Python environment + uses: ./.github/workflows/actions/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Check lint correctness for Python ${{ matrix.python-version }} using Tox + run: | + tox -e lint || true + diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100755 index 0000000..fabbb7b --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,12 @@ + +=============== +Main Developers +=============== + +The following lists the authors (active ones are bold) that contributed to upstream (or to some fork) of logki: + + + * **Tomas Fiedor**: |github| `tfiedor `_ |email| `TomasFiedor@gmail.com `_ (original author) + +.. |github| image:: ./figs/icon-github.svg +.. |email| image:: ./figs/icon-email.svg diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100755 index 0000000..787dd42 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,7 @@ +Changelog +========= + +1.0 (2024-04-19) +------------------- + + - Main version of logki \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100755 index 0000000..ddcec33 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,36 @@ +Contributing +============ + +In case you run into some unexpected behaviour, error or anything suspicious, either contact us +directly through mail or [create a new Issue](https://github.com/Perfexionists/logki/issues/new). + +If you'd like to contribute, please first fork our repository and create a new dedicated feature branch starting from +the `develop` branch. Pull requests are warmly welcome! We will surely review the contribution (possibly request +some changes). However, please follow these guidelines: + + 1. **Document your code properly**---refer to + [sphinx documentation](http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain) + for the format compatible with our documentation. + + 2. **Test your code** within reasonable code coverage. The tests should be in the + directory and should achieve a suitable + amount of codecov coverage. + + 3. **Follow the project formatting**; we recommend using the [black](https://github.com/psf/black) formatter. + + 4. **Commit properly**: write meaningful commit messages; we recommend to write first short line as a short + description that can be included into the following template: "This commit will ___". + +Before considering a merge of pull requests we want the feature branch to fulfill the following: + + 1. The branch must be compilable (i.e. Github Action checks are passing); + 2. The tests cover reasonable proportion of code (i.e. codecov checks are passing); + 3. The code has no issues checked by codacy; + 4. At least one of the major maintainers has reviewed the code. + +If you think your extension could help others, please [send us +PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case it is, +indeed, suitable for wider audience and maintainable, we will include it in our +[upstream](https://github.com/Perfexionists/logki). + +*But, please be understanding; we cannot fix and merge everything.* diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..86904fa --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +help: + @echo "Logki - Log Analysis Kit" + @echo "" + @echo "For best developer experience, make sure to use a virtual environment." + @echo "For more information about how to contribute, see the CONTRIBUTING file." + @echo "" + @echo "Main commands:" + @echo " dev Install all dependencies and set up an editable environment" + @echo " install Install the project" + @echo " lint Run linters (black, pylint)" + @echo " check Run static type checker (mypy)" + @echo " test Run tests with pytest" + @echo " release Generate sdist and wheel" + +.PHONY: help dev install check lint test release docs docs-release docs-all docs-html docs-dirhtml docs-latex + +# Base build requirements are not installed automatically. +# Inspired by https://meson-python.readthedocs.io/en/latest/how-to-guides/editable-installs.html +dev: + $(info [INFO] Make sure you're using a virtual environment for development) + python3 -m pip install --no-build-isolation --config-settings=editable-verbose=true --config-settings=setup-args=-Dbuildtype=debug --editable .[test,typing,lint,docs] + +install: + pip3 install . + +check: + python3 -m mypy ./logki/ + +lint: + python3 -m black -q ./logki/ + python3 -m pylint --jobs 0 ./logki/ || true + +test: + python3 -m pytest --durations=10 --cov=./ --cov-report term-missing:skip-covered ./tests/ + +# In the CI environemnt we want to see all the tests and want coverage report to be in XML +# because the results are being uploaded to Codecov. +test-ci: + python3 -m pytest --cov=./ --cov-report xml --cov-report term-missing:skip-covered ./tests/ + +release: + python3 -m build \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 1c80587..66fc197 --- a/README.md +++ b/README.md @@ -1,2 +1,102 @@ -# logki -Logki is a prompt application for analysis of logs mainly resulting from performance profilers. +# logki: Lightweight Performance Version System + +[![build status](https://github.com/Perfexionists/logki/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/Perfexionists/logki/actions) +[![codecov](https://codecov.io/gh/Perfexionists/logki/graph/badge.svg?token=3x4Luodr84)](https://codecov.io/gh/Perfexionists/logki) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/a704486b4679442cb2a53173475f79ca)](https://app.codacy.com/gh/Perfexionists/logki/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) +[![GitHub tag](https://img.shields.io/github/tag/Perfexionists/logki.svg)](https://github.com/Perfexionists/logki) + + +

+ +

+ +Logki is a log analysis toolkit: a prompt application for on-the-fly analysis of big logs. + +## Installation + +Note that we are no longer maintaining support for Python 3.8, nor do we support Python 3.12 +(this is due to some of its dependencies). Logki may work, but we strongly advise to upgrade your +Python to one of the supported version between Python 3.9 and Python 3.11. + +You can install logki from pip as follows: + + pip3 instal logki + +Alternatively you can install logki from the source code as follows: + + git clone https://github.com/Perfexionists/logki.git + cd logki + make install + +These commands install logki to your system as a runnable python package. You can then run logki +safely from the command line using the `logki` command. + +It is advised to verify that logki is running correctly in your environment as follows: + + # You can run this only once: it will initialize the requirements necessary for testing + make init-test + # Runs all tests using pytest + make test + +or alternatively using Tox if you wish to test for more Python versions +(see the [developing section](#developing)). + +## Developing + +In order to commit changes to the logki, you have to install logki in development mode: + + git clone https://github.com/Perfexionists/logki.git + cd logki + make dev + +This method of installation allows you to make a changes to the code, which will be then reflected +by the installation. + +If you are interested in contributing to logki project, please refer to +[contributing](CONTRIBUTING) section. If you think your results could help others, please [send us +PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case it is +suitable for wider audience, we will include it in our [upstream](https://github.com/Perfexionists/logki). + +But, please be understanding, we cannot fix and merge everything immediately. + +## Getting Started + +Simply run the following command: + + logki [LOGFILE] + +Contributing +------------ + +If you'd like to contribute, please first fork our repository and create a dedicated feature branch. Pull requests are +warmly welcome. We will review the contribution (possibly request some changes). + +In case you run into some unexpected behaviour, error or anything suspicious, either contact us +directly through mail or [create a new Issue](https://github.com/Perfexionists/logki/issues/new). + +If you are interested in contributing to logki project, please first refer to +[contributing](Contributing.md) section. If you think your custom module could help others, please +[send us PR](https://github.com/Perfexionists/logki/pull/new/develop), we will review the code and in case +it is suitable for wider audience, we will include it in our +[upstream](https://github.com/Perfexionists/logki). + +But, please be understanding, we cannot fix and merge everything. + +Links +----- + +- GitHub repository : [https://github.com/Perfexionists/logki](https://github.com/Perfexionists/logki) +- Issue tracker: [https://github.com/Perfexionists/logki/issues](https://github.com/Perfexionists/logki/issues) + - In case of sensitive bugs like security vulnerabilities, please + contact [Tomas Fiedor](mailto:TomasFiedor@gmail.com) directly + instead of using issue tracker. We value your effort to improve the security and privacy of our project! + +Unrelated links: + +- Check out our research group focusing on program analysis, static and dynamic analysis, formal methods, verification + and many more: [VeriFIT](http://www.fit.vutbr.cz/research/groups/verifit/index.php.en) + +Licensing +--------- + +The code in this project is licensed under [GNU GPLv3 license](https://github.com/Perfexionists/logki/blob/devel/LICENSE). \ No newline at end of file diff --git a/examples/example.log b/examples/example.log new file mode 100755 index 0000000..57d4bf9 --- /dev/null +++ b/examples/example.log @@ -0,0 +1,222 @@ +449651305717147:(21845:21845)(kfree):call +449651305724100:(21845:21845)(kfree):return +449651305725579:(21845:21845)(kfree):call +449651305727153:(21845:21845)(__kmem_cache_free):call +449651305728525:(21845:21845)(__kmem_cache_free):return +449651305800008:(21845:21845)(kfree):return +449651305812030:(21845:21845)(kmem_cache_free):call +449651305821701:(21845:21845)(kmem_cache_free):return +449651305830381:(21845:21845)(syscall_exit_to_user_mode_prepare):call +449651305839140:(21845:21845)(syscall_exit_work):call +449651305849913:(21845:21845)(__audit_syscall_exit):call +449651305852432:(21845:21845)(__audit_syscall_exit):return +449651305854838:(21845:21845)(syscall_exit_work):return +449651305857253:(21845:21845)(syscall_exit_to_user_mode_prepare):return +449651305860482:(21845:21845)(exit_to_user_mode_prepare):call +449651305863155:(21845:21845)(_raw_spin_lock_irq):call +449651305865704:(21845:21845)(_raw_spin_lock_irq):return +449651305867916:(21845:21845)(_raw_spin_unlock_irq):call +449651305870599:(21845:21845)(_raw_spin_unlock_irq):return +449651305874335:(21845:21845)(__fput):call +449651305877772:(21845:21845)(__cond_resched):call +449651305879997:(21845:21845)(__cond_resched):return +449651305883346:(21845:21845)(mutex_lock):call +449651305884906:(21845:21845)(__cond_resched):call +449651305886964:(21845:21845)(__cond_resched):return +449651305889290:(21845:21845)(mutex_lock):return +449651305891884:(21845:21845)(_raw_spin_lock_irqsave):call +449651305893291:(21845:21845)(_raw_spin_lock_irqsave):return +449651305896600:(21845:21845)(_raw_spin_lock_irqsave):call +449651305897845:(21845:21845)(_raw_spin_lock_irqsave):return +449651305904870:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305907734:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305910259:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305915942:(21845:21845)(irq_enter_rcu):call +449651305921833:(21845:21845)(irqtime_account_irq):call +449651305925693:(21845:21845)(irqtime_account_irq):return +449651305929083:(21845:21845)(irq_enter_rcu):return +449651305936148:(21845:21845)(_raw_spin_lock_irqsave):call +449651305940816:(21845:21845)(_raw_spin_lock_irqsave):return +449651305947899:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305950353:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305952634:(21845:21845)(irq_exit_rcu):call +449651305955607:(21845:21845)(irqtime_account_irq):call +449651305958536:(21845:21845)(irqtime_account_irq):return +449651305960003:(21845:21845)(idle_cpu):call +449651305961408:(21845:21845)(idle_cpu):return +449651305962940:(21845:21845)(irq_exit_rcu):return +449651305964981:(21845:21845)(irq_enter_rcu):call +449651305966218:(21845:21845)(irqtime_account_irq):call +449651305967360:(21845:21845)(irqtime_account_irq):return +449651305968847:(21845:21845)(irq_enter_rcu):return +449651305970808:(21845:21845)(_raw_spin_lock_irqsave):call +449651305972420:(21845:21845)(_raw_spin_lock_irqsave):return +449651305974211:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305976131:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305978135:(21845:21845)(irq_exit_rcu):call +449651305979253:(21845:21845)(irqtime_account_irq):call +449651305981001:(21845:21845)(irqtime_account_irq):return +449651305982200:(21845:21845)(idle_cpu):call +449651305983705:(21845:21845)(idle_cpu):return +449651305984769:(21845:21845)(irq_exit_rcu):return +449651305986522:(21845:21845)(irq_enter_rcu):call +449651305988310:(21845:21845)(irqtime_account_irq):call +449651305990191:(21845:21845)(irqtime_account_irq):return +449651305991169:(21845:21845)(irq_enter_rcu):return +449651305992998:(21845:21845)(_raw_spin_lock_irqsave):call +449651305994149:(21845:21845)(_raw_spin_lock_irqsave):return +449651305995996:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305997094:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305999290:(21845:21845)(irq_exit_rcu):call +449651306000856:(21845:21845)(irqtime_account_irq):call +449651306002263:(21845:21845)(irqtime_account_irq):return +449651306003488:(21845:21845)(idle_cpu):call +449651306004589:(21845:21845)(idle_cpu):return +449651306005970:(21845:21845)(irq_exit_rcu):return +449651306007730:(21845:21845)(irq_enter_rcu):call +449651306008978:(21845:21845)(irqtime_account_irq):call +449651306010408:(21845:21845)(irqtime_account_irq):return +449651306011786:(21845:21845)(irq_enter_rcu):return +449651306013923:(21845:21845)(_raw_spin_lock_irqsave):call +449651306015042:(21845:21845)(_raw_spin_lock_irqsave):return +449651306017104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306018366:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306020129:(21845:21845)(irq_exit_rcu):call +449651306021165:(21845:21845)(irqtime_account_irq):call +449651306022889:(21845:21845)(irqtime_account_irq):return +449651306024142:(21845:21845)(idle_cpu):call +449651306025704:(21845:21845)(idle_cpu):return +449651306026937:(21845:21845)(irq_exit_rcu):return +449651306028874:(21845:21845)(irq_enter_rcu):call +449651306030361:(21845:21845)(irqtime_account_irq):call +449651306032054:(21845:21845)(irqtime_account_irq):return +449651306033084:(21845:21845)(irq_enter_rcu):return +449651306035164:(21845:21845)(_raw_spin_lock_irqsave):call +449651306036445:(21845:21845)(_raw_spin_lock_irqsave):return +449651306038223:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306039225:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306040914:(21845:21845)(irq_exit_rcu):call +449651306042387:(21845:21845)(irqtime_account_irq):call +449651306043823:(21845:21845)(irqtime_account_irq):return +449651306045094:(21845:21845)(idle_cpu):call +449651306046799:(21845:21845)(idle_cpu):return +449651306048282:(21845:21845)(irq_exit_rcu):return +449651306049905:(21845:21845)(irq_enter_rcu):call +449651306051063:(21845:21845)(irqtime_account_irq):call +449651306052677:(21845:21845)(irqtime_account_irq):return +449651306054156:(21845:21845)(irq_enter_rcu):return +449651306056001:(21845:21845)(_raw_spin_lock_irqsave):call +449651306057348:(21845:21845)(_raw_spin_lock_irqsave):return +449651306058914:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306060465:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306061750:(21845:21845)(irq_exit_rcu):call +449651306063251:(21845:21845)(irqtime_account_irq):call +449651306064998:(21845:21845)(irqtime_account_irq):return +449651306066683:(21845:21845)(idle_cpu):call +449651306067866:(21845:21845)(idle_cpu):return +449651306068994:(21845:21845)(irq_exit_rcu):return +449651306070886:(21845:21845)(irq_enter_rcu):call +449651306072286:(21845:21845)(irqtime_account_irq):call +449651306073883:(21845:21845)(irqtime_account_irq):return +449651306075087:(21845:21845)(irq_enter_rcu):return +449651306077129:(21845:21845)(_raw_spin_lock_irqsave):call +449651306078428:(21845:21845)(_raw_spin_lock_irqsave):return +449651306080104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306081289:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306082424:(21845:21845)(irq_exit_rcu):call +449651306084461:(21845:21845)(irqtime_account_irq):call +449651306085655:(21845:21845)(irqtime_account_irq):return +449651306087347:(21845:21845)(idle_cpu):call +449651306088245:(21845:21845)(idle_cpu):return +449651306089812:(21845:21845)(irq_exit_rcu):return +449651306091789:(21845:21845)(irq_enter_rcu):call +449651306093231:(21845:21845)(irqtime_account_irq):call +449651306094161:(21845:21845)(irqtime_account_irq):return +449651306095499:(21845:21845)(irq_enter_rcu):return +449651306097027:(21845:21845)(_raw_spin_lock_irqsave):call +449651306098434:(21845:21845)(_raw_spin_lock_irqsave):return +449651306100032:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306101322:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306103370:(21845:21845)(irq_exit_rcu):call +449651306105076:(21845:21845)(irqtime_account_irq):call +449651306106109:(21845:21845)(irqtime_account_irq):return +449651306107586:(21845:21845)(idle_cpu):call +449651306108988:(21845:21845)(idle_cpu):return +449651306110299:(21845:21845)(irq_exit_rcu):return +449651306112028:(21845:21845)(irq_enter_rcu):call +449651306113911:(21845:21845)(irqtime_account_irq):call +449651306115148:(21845:21845)(irqtime_account_irq):return +449651306116955:(21845:21845)(irq_enter_rcu):return +449651306118563:(21845:21845)(_raw_spin_lock_irqsave):call +449651306120193:(21845:21845)(_raw_spin_lock_irqsave):return +449651306121698:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306123240:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306124573:(21845:21845)(irq_exit_rcu):call +449651306126425:(21845:21845)(irqtime_account_irq):call +449651306128107:(21845:21845)(irqtime_account_irq):return +449651306129739:(21845:21845)(idle_cpu):call +449651306131113:(21845:21845)(idle_cpu):return +449651306132204:(21845:21845)(irq_exit_rcu):return +449651306134263:(21845:21845)(irq_enter_rcu):call +449651306135755:(21845:21845)(irqtime_account_irq):call +449651306137490:(21845:21845)(irqtime_account_irq):return +449651306138257:(21845:21845)(irq_enter_rcu):return +449651306139967:(21845:21845)(_raw_spin_lock_irqsave):call +449651306141326:(21845:21845)(_raw_spin_lock_irqsave):return +449651306142941:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306143993:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306146020:(21845:21845)(irq_exit_rcu):call +449651306147271:(21845:21845)(irqtime_account_irq):call +449651306149021:(21845:21845)(irqtime_account_irq):return +449651306150343:(21845:21845)(idle_cpu):call +449651306151936:(21845:21845)(idle_cpu):return +449651306153351:(21845:21845)(irq_exit_rcu):return +449651306155400:(21845:21845)(irq_enter_rcu):call +449651306156749:(21845:21845)(irqtime_account_irq):call +449651306158440:(21845:21845)(irqtime_account_irq):return +449651306159673:(21845:21845)(irq_enter_rcu):return +449651306160914:(21845:21845)(_raw_spin_lock_irqsave):call +449651306161783:(21845:21845)(_raw_spin_lock_irqsave):return +449651306163150:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306164098:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306165525:(21845:21845)(irq_exit_rcu):call +449651306166404:(21845:21845)(irqtime_account_irq):call +449651306167628:(21845:21845)(irqtime_account_irq):return +449651306169374:(21845:21845)(idle_cpu):call +449651306170457:(21845:21845)(idle_cpu):return +449651306171490:(21845:21845)(irq_exit_rcu):return +449651306172920:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306174229:(21845:21845)(_raw_spin_lock_irqsave):call +449651306175561:(21845:21845)(_raw_spin_lock_irqsave):return +449651306176842:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306177852:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306179116:(21845:21845)(mutex_unlock):call +449651306180884:(21845:21845)(mutex_unlock):return +449651306184624:(21845:21845)(_raw_spin_lock):call +449651306186282:(21845:21845)(_raw_spin_lock):return +449651306188480:(21845:21845)(_raw_spin_unlock):call +449651306189664:(21845:21845)(_raw_spin_unlock):return +449651306192308:(21845:21845)(dput):call +449651306194809:(21845:21845)(__cond_resched):call +449651306196639:(21845:21845)(__cond_resched):return +449651306198886:(21845:21845)(dput):return +449651306201957:(21845:21845)(mntput):call +449651306203024:(21845:21845)(mntput):return +449651306204139:(21845:21845)(kmem_cache_free):call +449651306205971:(21845:21845)(__slab_free):call +449651306208669:(21845:21845)(__slab_free):return +449651306210733:(21845:21845)(kmem_cache_free):return +449651306212495:(21845:21845)(__call_rcu_common.constprop.0):call +449651306214769:(21845:21845)(rcu_nocb_try_bypass):call +449651306217920:(21845:21845)(rcu_segcblist_pend_cbs):call +449651306219060:(21845:21845)(rcu_segcblist_pend_cbs):return +449651306220460:(21845:21845)(rcu_nocb_try_bypass):return +449651306224060:(21845:21845)(rcu_segcblist_enqueue):call +449651306226501:(21845:21845)(rcu_segcblist_enqueue):return +449651306228010:(21845:21845)(__call_rcu_common.constprop.0):return +449651306229147:(21845:21845)(__fput):return +449651306232040:(21845:21845)(__cond_resched):call +449651306235163:(21845:21845)(__cond_resched):return +449651306238018:(21845:21845)(mem_cgroup_handle_over_high):call +449651306240262:(21845:21845)(mem_cgroup_handle_over_high):return +449651306242616:(21845:21845)(exit_to_user_mode_prepare):return diff --git a/figs/logo.jpg b/figs/logo.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b45ddeaf19860f6bf17d016c64e317533e9c58df GIT binary patch literal 148160 zcmeFXbzD^6*FQRRDlG`Y&>cfb2_w=aA&oF}h;%D3gn%N5iVC9AA)$z(Vju`8g3^sj zhXP7UGjsQu0n~5&zRz>-eV%{recQjE&M32zeff6dn*P7c{nRNIV#9V zN+O)Z5b|gtM5Ftemr~oQyO=(h&jHBIe$mP6$7pL%=^RD((;v;Nl3NS!gin}`mxQjdbgt|ZiFcv4N0QaA|m;HQ$t@O`ZsT`*; z6!U_?2>YCXaITZXSvS`JcLyoiqb@j+ym zeI(tF3hH(FQJPR&hl$t?9(hjWLC)ml>)?ERPtI9Q%19L_s0#c02UQ~@#O{m*ud=UW zXAW0Ave2H+B0HCBt8WPU^;{yK+xvUNSQ#^jsS|Vo&)Ivm96bUGQ;!z2RHlkBnN^ z%ZNY!J2}d+V|r8kyb~R|eBWLd4$vL9kLzPfQRe}zq|8S%TUM>oE(6A$8LV8 z{QLZHaN5hJf0rDv%TRLUxb2RN&UeLMoyFyslfR2Ypo_CtfRAfnh=ae2s+)^8&x<#hJXgvXU7ai_Bm9w4P*gqo1rMStY9 zhqIHStB=2zL*N+?NIi)&zAkPakWvnTLH;hG`T;IyU3s7tT$Lf)B>r0kOakYQ{n^fV zcn1VJcssf1s5?oDBYbdbp@4HBi+ub;j~IA3`TIa#Lz%b)_=1Aw;ds^srK%$VMhE`G zXq1Pyt50;UGgOR1h4v*m|B&Pa{=z%m$loUzlr6BdTd<3N0PrQGz?t8bGbZm3r#J=q zpAEJBf5GzK^W#17yYTLU{TopfLoe1>qL$8bL)ZK5*)7U!adytR;D0*c0s(W(wlzoN)HC+1|}9`FBAE=(8S}ZdfDZz5A&z^X54di=wUFC{$0cg?jr7A zaMFIv0qR8VL#XS#pq@h@&ztKOD(mF#;Ncx>MJj}dA>~8F5Ff}UA|xOrWRM1fkIi`t z$!s2cJpr!49pV5fg>bxf{MrEm0%{T%!d#LHK|xAnMoh{;Xm(1H191epp=4nC4FEMC ze_tN}C=g^x0R$iPI}roN@83_UsdK793E|)!7{Fg-3_&#PCPRH_apZJJk~(p8M0ZjzGsh7&?K4y*$qTu{ z5BS4IXfo;?1w72tYK|nP65l9rg^g9R)150_c~f>dk?r&v`Kn7SYbUev;8&?yo$~@Y zpLiRtgnfvtORkVNM!@USSLmH?x-PSa=+WmGVKpkZ z2#E+_1bHz8`XD0Oh{GWI?0f_SSYjFwH7XHO0%C#~IejGp3LG%lX`r8oi3nk}2zF@b zLE=NijPH6W6XW$8o0D!&c-hhSvcDmJ;EjMoKl2c?APz+_UVf0Vof6d2dLY^3LAZXt zz4<_;Isyd^fD>CH%n_#9CfP>uC*1=BeHA4nLPA2sz4of8xRZ~Ugs-QEk8gm4lmA(X z{T$$vLVzp)|L*4jxCWU3eWNN4h9b_Ak^}uoNXQ5Xi0u(}h|_!b2*P-y|F{-tM+5%r zs|6ycA#)fY_Yfjre{vS*FYUC^W8E)w@lb@5y4kx{DD{=xM`bcSg#fR|>BJb-RDi4{D zYxaZUF3athd#9E{ubwY_dpgfLe@eY4y_CA0rZ(c;&02-@_L8GkCgLsbhdP>_+Lgxa z%r`!a#@7@{EC?hGJXSq-oG+HykMed(d*I+0*(2|SRM|^xzPy+#d~c$bHRc4psL}cI zxv?u;Aq2G#zQi_)NUoL2=>AM|&t7-u)bx@2R!&LZRCV!3P?t>OY~>v7F;O%r>g4O< z+k|g>%a=-{B($W)D_qBX^3o@i4z+#s)D|Kk46@XGKTBu7qMqMfz{Zy3QkW6h@X6*% z>#rlCVd|c}$>jrNOkdm$?~1&zpl`dd;hg>MrUDWZ_iIx9rd2@;d)cUt$0ALrtp2T| zSE>XrGT)pZu2sJ)`|^gBs8PU5a&`a@+KRLna78EJikE+I1#w63=s8MmM;aVg5dQ;k z5U9Uv_J86E1VS9Z5O9USex7ii3i956;+c1cySd!AkYzjORY!992*iE4z^$Nh9%V zLW3CLO~DMSyv1$vJexxjch&ksc`I%o>4<|BqRU*bj;TL!n;Y^w&63s|SpTh9fBx;b zZ9%!9eMGu7U+-8rR$2czD}9cvs4Np=LtFd9JoP5ohl9D>Jc#z1t7Lj_TDejuBEQBx zGPQNvdi`~CmEWXmWbt_g$}UNo!=r`mw#yo+<6WLjI{ljm+AW6o_1U8`W{WA0*Ac!F zc9CW)CjrjqC>UCSZ({VpUmFPCZaE9S$RaXjF;|&K$x`a#eg!2onNbC{ol&R zZ{~-4mOM*}v5~Y2q^X+C?Sqr0zt2QGLhDZ@n6+|CJ=IIpC0-+AIb6-O>QR?ZXHBDC zjk)`6=2OJ`+aa;1o=Rxk=sY30BWioMLHXQW&4Zn%Q)siD{XR|SvEOpzQ{tcKmpM3E ze`U!!@E|fS{6VJMBiqg4fzx7yJuKubxzDei5wj3kxu>V59PqGno564R%eCK zL;%=`0QLtP{Y$ceS{-&yVoC%#f|QgPT*3g=?ajeRNKDN^2|EP~f;qy}V5$h3{aQ|f zAOa=*FEXQg;;vLaSpL(uAb5al?UVW;vi5brH8?VJK{z2CvQgQ#@izaFVE&QJaA^v$ z7nG>`Tm~g8j?%zCP{QJvEo_g;0JC`^JP{sy_kh`K|Kq~{%xwSVr33%W**#+OXwVX6 zBv#JODnfnbc{fnmlJ8k0W#;pW{>6_^eo+a95<--kgkHfoVls zG#4DGxteX?n?$Cd)~O3uBoDl+Lv*se{Vc^1*s=75e73Gj)U^zLJ&osYcn(qDVzMW4 zStFobQ-3#gwT!}|=@ZdSHp~1J#b=7bEj2sxrSkD8lJIigD?Zh>lQF@feCZ4NX*u`c zn_|j`$=cY=t87-C*Lof$%@LhMs*$^zxE@n{lquLyKlV)CeP${~=DZZSk;cL|>UQz4 z<8#yeOhFrL(<%>#bS;iyw6>{8A6zjVVjI6L!^2WK6YzOZM~Q8@#!~29rz6CuhqHnq9QzQ(E}$<%zXR+enH!+*pkG^!k%X z<2~{&Xfvi6Kg@IO|%YpN`2iFyz$A(QXhUm+_Orj zMX!W%qwDE|#CzSeL?>RDpLo9XSR~v#zg6bVRCklZ#8+xxBx%~mthK9W)hf%Delne+ zXw??ydV9B9>WzG|gQ2wI*SIH3&YaDLA72R*Zj}~Bm+7%#I}-vkTZO)+A9cRW`yyBI zdm{n1uw5R96^%WhJU%CY2d#OwTODlR?vg?r<%Dz03KtTsiB-bIQT6OO?q@2p6k zAYw?$5ivw*cw(b<7wplGJUv*grtpyZt+lZ1KcMD+mDRuw2*+x2c#@NnL?~GQ&nxhs z=q;0v!1XZPS?29M1s+Fszsu$`e4TgT^8y4hH6i^sq+?mM?-*sCzvW!lUXRkiO5Od& z%v>G%BPboE2vYrs+#OBbtCWw*HLt5kUlQJ|nwD}}=4tfqWZdGn{D~pGV7mDhE?4ro zd(K?AMyLAIEa8v$C%4NEKc$!TV7kO?kmo*gmP06mV!8Dk*L#YN!!s!eO%Ek^Vv+Df zv0f+J8LwW2%xY2Mn=l)8K#hs2Rav8X^%JF)~4yX#SwKkAV)rj$fwJIv;C>s z#F}_0&B?XbH7Lsu$T%l7;3}2G zucn}*v&o%aSHf&xvdUwJ4-?$){Ls<6G@JNKyyH_U!=1ZVLtUK0h#M9&vyv2-ovAVD z?5SfZ<^@itc&fYu4r#DHTRTtFk}rj|#@tFCO$hz$8+)HO&V#egi~hi5*s8EqTW{%f z^i+1mMKSUus*1M0vq#G_H;CK@R0E1jHLCpVEm^t`iMqV(AQ`&;&WM)oYOB_#t@0Y4 z+AI=0y}2P={)yWDiF ziOlq0=&mF`H2+4|=Az{a>7ne|bGD<6>b86Nf1v9xcA8<^g=sk()XRm+`3Wbo zNVpV>N3pN<^^LH*mfevx{VLl9gV;UGB_PiBAO_$jBp|>Kir+a)Mu3p~2N_~cwc)Jb14+Ux%Bl}TZ}dcUYFtQ!j9`LxO_U4=)jixi)IfhE z%Bkb+Brd6hP=J0QVvySVfz#AKC;&RS){=qtQZfjIqnxL-Rl$=bPE!vrms5cbUcTTc zZSOcv8X+esgTVcPofS|QAt@~-Evq04I7s`ys01g11Fr=0ZzaG|;1t@+7uv%~gFVy# zc`ucBN+W?i_KHoJis=)ck+!V9$5Q+eflO zgnM)BiNS3&1@Ddg7}mivFZ-36ZHErC#BFKJ9B?>$594RoK$>xE;hlIG4V$aU_=jE< z)Sz0|gV7rboh>SJXMD)p`7oIr!8MvAPmNnj^j%{wx;wslt;!a9*lS{d zX2eo;tG_~Y)VRFz0TU_Xj3YTimj_3@r2rlu#&ulpL5+|~06luqmf zMEv|pi4BvXjVwG(X{irWiSr0*jCJk}YDu9FHZS1a>}&Akdif15lP;k+<4N#nZA&ESDI z!0`Fgqa95s@_gUCIm$&kap#eb+#=13f(%?b#*w71T}p2@XRpck8JYS%!5sinBPjQ_6-49+PUw41;=>4L1UV_GTQoHR zIOn4JGrRvh@Oyb^z{?;`B0wlOLn0{Y3};H_2cJK-Xa&#a8K&o3+MRQH%!^$l^M-oH zbr9Cj3UK062xEj{wn4UDyw2`U2At(di#vnNbOM=)I}hATgxzG+lG#l~d?x;xh`UFD z(O36O0XwGXSVVLbf_Lv51VKE@?n*vR0lt5&gs|KnMHsKYr;h`qNWfnMCH|W#{k4$- zB?(8#(X72g*~L%OnP2-R8zvrezuV7;{U|!oGGohqeJ+Wcu(+x%>i)p=_`4tcF^PT> zEMHGP8#>!JYJXSc#}8%gD^;E^!)>eU9OT?}Lh@#>meBVJ#4TUpxIS2STt3V8L$)|y zDBnF{l5-b?(w|v`rF`Z$7kRW?R4qr{pB`*z{=%g0***E<=xHz2(@7p3FGL#NpKrUn z89J8A8l3A9)MYfGPXC7UKxVOe`}(9#2)Q-ayUMooo2;fUU%Y&wgu z*W~66OqQGMxf;y1ehkv-B}vs^oU$By_E}{E_2@)z$~g12j*?ol@%WlD0a4ZV3~Al_ zN4sD6--=8Nlh;Ny*L_iz8V>3`>SldueYL1@(opsotoqGe;j>``Uk25u6o=%M$m|p> zSHc4%&9bBDJ~C2AK75VIpAB;-h=-1Oun{%?#QoaIaO++!zcA4INW_}LnylmM^4+n62!_+nppRi zF>~{rT$$@)-ZJvUl7+zi($rO(sx-UKN`+fWxM{gevIRW5z2PZJsyVO9v9N#|`8@F8 zYLt3;6s>9^V6lgQ#cu7g7}-&|=e(xj{aR%^g08}LHvho0uF- z6JOk}%or;#^qO~13yRHlRXh!vhLgG^-w^5=nDZDOxSF5|JO5c-_0pH{GZyC-(%ix)Z-!Dh}K^U^ltM93!KhQ6ux6`IeOr9 z&lKDJx6Xmbi)#Jfy*vr8cxq`7hUrTQNG%gp7%R~3U3etPP;4P|OF;ZrLSf3uU?wwu z-*kR-Hmeq=+PIoi)cGK90lus0it=<%R#!8plx*grhqxIBVuTy7*JKZktKHHmK%)u&W;msgHUezBbYDn(7>X;a<7%v~yF}TdxDQY1bCUSpS!~Qi-vgO(r zhoMxALhZ(5M1g+a_jFxLl`f)-m?tS+c6!0|#;Hw7)Jisq-1pz|lW#E6(i26XcwRY= zJB<{Ms;t%pK1Om-1kaV)Y6gwj=UGw^2*M6tF#Xy3-S&eWg1%Za^J!P`i_U|dx2Zd& zD_bh|_{|pZn-zi{;t||~7;x4H4)6Xx9sHNf^e1)A^^M1L`q?_`4~x4Yr(dQ&JVImm zH)n$LM<~+wsFn;k4h%%7LE6BHk0BHh z^4UkTW#Xmw=J`*|xj)I-{{q4Pv5DMctO%u(2_jv4`?*exK4KB4HDG8% zoNBFM*=jVh9n%xq@=ZKYBIL2{@wSbf?7NEnhkmNb(>8rx37Z!<`D7&BTAtD0@@X*A zcVwp~kGX%Sy4bvpDIl4Eo3Hhz2U06!%Ri8@4_j)OD0;3mu0;*?!~R)`;WgJx(ae#= zvdNvK*UtP2XRlY^3vc(O44=RMI>_*)^;$9QW83doLDNeMJ&At7E`y&I{PTD=YXxG| zAKn&VE9K?jfBSq$cy=|jBJ6f_o_TyJrAE_mLvr?X`qozAJ^%8C#gh@xnC zmerDw!28NDPv=F5>$OGyyWjN)O^W0qQ%{vCv6Ji2+-Ola_Z7?MbX!1F8R=QH=vuGZ zV)*R%9WJip?avu_TfVS|Do$iRn3VCm-pB7bAs}uTjwwR9E66udz(!3WW${`@i|JjG>Jjdb7N2^l1rP))R3LYIMUjE5kd+f5B8h;J1%9f?U87&Xbvt2mQ zfPgQv<;x$MHGiMx#a{Y2Y^j;9a{|>%a?FIr1pYpgsUY%ARMIc_f+4y$1j6! zp9zq<(Lt+DD?S{vOm<-^P|3@0OpKcCCudI+C%co7SnHhK$q%XPTn=|+W=Y=L&DpTN zo^5JtDU&&lsyOHRGvtHzeOC*MEK|!X)FRIfix30mKbz0njz4HJw40Qjmi#!FYWL+z zO4Q)9Yw5?YhSi5QKC5VWdWJ=wh&H*uTP|OmB;w+)7!}%UzNKa{s#1NQi35bauMvcE z>36?=$VL=o8|pfsD5;(yeY}Re&srzHZmKxj?Q6ck>l{Ocr*xLgYrLm5Q=He{dRz=n z4_3CaJrSI6Db3@Y_QFUmJ)3JrVDpe3$Miv`hg042*RLyPDu01ZXz*QnmZ5%FB(nBK zWv7GJtn|RUVLf8lr-&mr>r>Xa9zUjg{tCU+ljJL^YF|>}#G-zaHP|t7HR{pUH|Ij> zj!R^t)z7EY@>!}1LkLD`ZcuZvKQqbIVt*e~gh7Grn9@#C31k>jTX{ z5!OFGG5W9Ve$@WpCb>OM`9JM`c9T&@9ZE&q-YXEHfoCTb1mLG^z)$fqdo%r8cKYXO z&f;EH`iCcYe-IMxSrh>Q%s0D6?X=mnJSsackWKm7p}w^m3$p5rvYZ6bxj4IG)>qu? z39KHb+&}U!hIm!8GOjS_o|6!JEK{KWt9i!5^ifrg`IWi+9_4QpUv`f4uY_2iHcj%G&oNTo4yJIwkmb|-nKN0|{s#fb{rw`dn#f{Zeq^7x|iGmVsAs`JcmYZoBLkrKlo5P0W}dGNMqKuO?r(3 zA@}F(5|V-legvQxV$ROh39lc4+@CtSk6XB_9`%Vy95l;#D1E5hfHk9=I#lpaVgrYt z#4&`hlZBsh4vn>#5C;c5+>Uii^es2BRMC1_bl$C)YiOTrF0*xavTYS z?l@^Kst%|p_`heFw_QbGBOEzyCf+E2*W&j{NwmxCf>`Sp3JDmcm0t3N;^W5fqVn(4 z-u?=b6M?qQLx+6DDKa$PR<4*Zo)I4Iy5)Y(;Nhg6>9 zDYAtzxEEw-=5~G|YC3g*B``;4^KvyC1uJLvAXWB9f!xE(e*MjQ*PnQ{aEZFFW~)%5`e&meEc z1LDuBSeBzW?+Ub@uF+F|!J^FF=|xITyUyNR6MpvLpzo^#vI>m%g6LPSG|RO%P)kg> zv+Buyo+g{Qs2|bJv z=HcxGy$kuK>^uI(?YH^buZex{J4xefapv0mcyiVO{q3*RFDTyg&RsY-f7wO(zM_bY7==HS>%_v6mk9kg85fVs6&WQs#g+li5prlk!J6%-}*thu1V6m zIxKgPG{NYRszCh@6P}eRM&bDv+qDh%&z!p_0%Mq-J<^LF%BUL8xpJ=Ng#4(Z*coi~ z`rz@%vok#0&wo6sFZ@)}J~tp~HWC(fgLI{*rJ#e-x9aSQKH4Gg;ZMO4YUcV&A6$ms zz{Kd|ZxA1^b1B#|yvT-({or8*O8%WOTTZ+!Av z8|xT*=TS{-gHxlEuQI1Ekas1P=zl`>7gHVGNlCDrBSKx|rfvIT=cR@nfzj$}>S)3U z02SDS|6tfrn4(6ghbs(bU;q;a?^uz;h>U4r1mFq`fx(RFV8qZh_`rfGBR>XIx0#E3Q8s#T538LCf36&Of1Z790FWy?0oFZEZpMUe1bwE zq9UxE64DaFQUbyv!q6lHWaQ+O6qJlqRE)w$SdIw)xBsxUFgkK#pdAqbH;j;ufQXI& z+W>ae1cXGyB&1~I6qHn8z*AZncvM3~NK8aRLJZ6#hycICi0Me^xg=Fd z8H^psxcwNVqOawU^PH%7%Vg5Az$@+OA45TTh?(UuD<8jrppdYP>`^&+1w}P=4NWa= z9oK6Scq#FE>W!PX($a5d6;*ix9kqN=ydXML-w=K16iHBwUiD^s2^W4t@;WQqkm$C$8mGyrtlg zHd$bD^zWcN#49t(w+NYrv+TcSSj_(|%k~ZXZPy@-8oX&sNJm5mL&7#bnRHTGf0v@v zwH720EXa+bPyGKcemj9uFgKlC$Rqcjwu1(v5od0qAngBZpZtRSY+}Y4RlVbNw~8J= zuIiTHu6!J$cllB}ub<|t+x@GA)q0}|^=G&|KR8wWB5f#~YqDmI4YMIbp0CV<-kRte60lt8Oj+OQBHKP7lz>_o!NStx@2o2t zH_5G9W{PKQ>CLOqFF9jjnLb!pc*e0}q+r;`A_CPK`cyatL;LPw_+Z8m_PL+`lsB^lIPFGhoQDLlk+E$Yb{D!ZuMjZ zLw7a`I9k!on32s%_!KH^0euS#`{J`T(ScW0b}eDGCcaItMGmv6>v?8~6&^XSw{53* z`te-jua~G#Z9&xRCW+}$z53s2IDJ zZU8?BO*CO)$A*C?-sop7w_suOsi+`yo$9D07AA2Hy|Yv^scGfg&5LlIP zYxt|rhmMMxm%}$BhJwne52n3z$HJodWM(4|L#s3ti0fcsA~X+7P#zJ}bxLeoMN2Ya z-srd*pjt56JJcxXbr*VZ5czzY7dg3nayxBXXvuKH^38KSoI#U78fQ?L&sPv(*)@x8 zUJeH2(pDiBHeNHTD_c&9)T>5dgtT^zDS(V&1VBp0MYaet4&wA?o;58V9Y3zW-5FaN z>V=-1H-Inj=3PfOH~uP#==%+zFrS@9EbNUzM1N4tfrHOq`s}RUh_zdI4j|!Cv({-m zH$8B9)^w}<_4=u1G(I}}*qKqp!r~IPYdnTCy3nKCI3a+ejIPyyIRJxhB_M@rPQ`@P z>@2ze2H#d5h8{^pvvJV_jP1a}DBy85-?$t$5|!`1l8o?X2ii$Y=m9Tefw0!N-NA$b zmxQx!Wnt)js1IhurA!H-NBI}pc8Jf`NNPPvbA{U^1g&LJg)yMpgpl*GdN^Sa+&2dz zpy?&zQ??tMr}+AK>pwZ=rchNlfD5iyO36|{8WTy>zfG{R;M#szDZ$;9`?lBmI7>}+@Qz8 z@W!o%)l4U4t-ZysHSDF^h}p76f@SA-i09DrPxA&oK8o;G22K=P1rDB0s#$xRH`fKk z4+Gzz0>J`?qr;mNR_I~Jly#kLB`i!;1iAIicy1Cz+7GAW6Oc&9K(Tmp;4gn*jzIQg z0egVPcj^-`jz>{z?O?$t@ZRyS0PJtnYnGc0w?;bl9cmEKgL66-_Kn8{^19)=&M`T# zBpZC|yF1P;#?X>z+>*GM!9m1Bn{W{aKruXsZrA*X*|>@2u%fl9ah9n_Z7L2 z8XAI$F-HS~F!bnySXjGm8(8+dLa@{3m-7J0HhW8G4S-;0NDl+cz!up?g1>2En)$ft2~=oR`W+wUX*P}m^HrU9UV4r_ zVSAy+#ZGUu27m*UZao07NLFYy0MJUj+!`d8DzUu`D4}DoGRm$Q?u`UctVGvo0eq47 zqrnUycaRSnaag{Do=$}bAq9`m1<#*Z>)PAWkn?D^zIz}?d2tDcoG*alO@o)(22wWw z7V|!&?IkI2p3eagvPR&$nuXMLH%!b?WIA4EH*0ofn(&3e^Jh6gAt=`X5}!=a0Gug6 zJB(wBo60AZ=Lcu!RSx|w9mn=k?#&F8G<7?_sNfBWhCowc^b}VSW;bQ<MKBH`v0_ai#5NR21zk@GaTQ|kRK7s3AU{>2tc<(4KT}-pSfJk+2 znCxmA0n(I$ISy1P$dqkfJ4O)SEB8R&h;g*qrsHd)$fORwWJ{z9;35ry_gd&FOpId4 z6bP@zC~A}Z`|w(42gv9I{7OUmHF$E=+C>Lm#s-qv#e@$Kf_i{|DFtB>YBQjf)}5Z^ z6zu{q^Dw(Cgb#cs|5@M`Ji>RuQT`IDPQ##j?w4Rt4fvoM{NT4$|FQ-H;J(4toRpna zV41;h?Eg{q|2fQ{0no$MP)JLiy`t~%w;RRw@d zjQj(N%>N3CP!UM0t68Cav;!5!w7TIHI&cY!+dF(J*Fa7Or1B4`Y%m%*n4B_&FQ)Jn z`p4VvI9empBm5x-{KFp{yHyomq(DNMBXLCv1@a73|GgRoAvtOprSs)_6!77mlF~z1m?7@w zPf5%;RHV}OmxGFwIC2sU-R@1r(4(l(?OG@CQc(FYgp`D;)Eyv3`Ug)#kh~9iWPEbL zLGcH=>7*UO0g9t1~8`w{qpg)LkU1?BgX9#}99LoWdqR5Jv@#&tZnYJl1= zhR1GeZ9hQ+c7epMt)F_6Q-sMH)jg&1fJmbr*6zzW_6|(20e8T+PaI ztb8Fbkb-aI^yZ$ER%OA}mqnAa$EmmFG zel~I-h^Jmuhw?yc&Rbr1k&JvZlD@*Yq3&c8z}r~jKwr2}d1!z`U*MfmI-$D5sRSv7 z=geh!3S@fPO<1jUj}zX_6IjS+oE%~JaU6a;lxjrlq6~`BorC-Qj*7O!Ev4H$)Nh|% zyGxTsJhEl+!gjq#>uIKESo!#J4xb&uUv;Ip(m0v5Hh4=0wFxWdT6BzCyjAo(sU@rP z6{0H0u1GYqG2!xi(>x}=2d!#jTFGTAZ46CJ)kPVPv#&C7I`M8>!$=pTnK z(4m+vwN@~e$fK5!HqGmDBq{a6^M*Cst<>9EsPQh!)zQXv3*+1~dS&1J?8;mvxg09* zjuWSRw;ZOsDv^*a5`CxOn{u+{0=#9EE#NzEEEdKgJL6(GQ}yEf7F@dFHa}cAvNdzl zb0*LxK=ZBPc(qyTsjl&B*Y*0Dx<{k^u6hpp8-H1^dRI;V!pU*dxbk2Rd-cxE?o8XK zU!z8EWxnVnNg8aMKV4wFekZPjQ-esw`)5`hvbHIUqIP&? z&~VyzL)^iJb)#^l`^8J9M|yPR{?F!oND4k%XB5z0c#pw;y?Sya$9o zzL0Ykmuv~sYB+Vd)EEoX?;l@ey2AY=nM|I&iqf~#_JrPvZ;RpnQBIxZaAk7+PMvXW zv3v?YhX4jAC0k$ZUsKhZ^*nk{^hZSLlH7K#*=a25kH6Pd7PElgeklCZvnxSPZX{%M zJfYmGYvTE*d3%?PAq9(QZqma)u4SZpso6^w4q{<_pn+)Duq?M#%5OWEyOyDLl=5g- zGFORow?X9{4KY5%s{^^o;P8g((PzyL4MviFFGep$^NeaC)rBXuV-g%QCO-%V;;^G#E&?=8j2{K$P_Nb_~bup~P(ByiB5=H$)Z-pUf;Yg1ZB zxi9C5o4^0T7^k6lwYLaSCuz0WnzwVipec}hIhbx~n*F4RYFqQL?v%Bbui4kzhDME? zy|VdZWiRiAh6**$=cErIEiZm8nw}NF!mMwEYZ--h1z=%b=*^y+<4jaO9??m!&|Ie< zXL>d~NGv}Y{(3k@<<=Fd1Lj#u2~+29U5nVs%m0jGTuN%HaSeEWU9s=kKxo>D%UYG1 zJr9hp6Pw#^$1plOzUHYv5^8gDEehVIqOCW48ZaEM7s@Ys2S#YW_x4(ym!vnHAbN|m-a4fo znp&@jo;N=JOn)+}@gqt+JY?zfSoO-)moJ-$#a^6L-SFEHd3%HY#V;1c2ZIt7(~LI? zuRl`e(vXknGGHA2fQ6}4HbiXXi+|<*aLz^xG|Y*MZA@9~WwJb2m_bd!dD(=IMK(0r zM(FX}*KY5Sa+iakACk|7xhuOpZVQAZ&8pksASgmal|TRryBH)Y~|O-!k;r;X(&1&r@OXI zlT&M&gjjg>?L18qdP1ic#6racbiDj;%-2zvaufKkw#~kf2ixa+ekmVXdT&T#;GJev zscEQu>xGXt3_EWn(Ib@lz9r9uD;*oJMM)$}Xq9Lq7Z>eP?eq$V>;TtRy-s{LrIc@! z&qOBHSM)RxxsWxZFTa3^SbL6zF`(``AuJQ0-pygB8G3wdo+S2diCK}Ge`7-e7Iuj# zm#Fs}TKLHV7M4ZvURmI3$8AR>2tYI?Tsu3=!H^qSM^>VrrPi>GPPDJaX~p@F$Ccj58(0&G+G|s%HdERuK~~ zu1MANmTc)+F4xd+52;juDy!_!wzGnKU+sI9S#}~*P_GolVlzW$_0jk0V->oS2bJ8I z3Ww=r6W|gFlSF-<@b4&!%n{GA3c12ct&xv3o3xm8Bm0r^dgY{(P)#t6)54TtH zmdyqA#anXen*DjJD3>Y8gTxV^1NNAS?&6V7wA)LT8Vr*B;QO@Pk5f|-;Ph>kzoHTxA zt{^EhdeTGF;?UI&)dyD`<={e_tdljD7ax`-#h!jsM4aK0ce?e3hP}$EHvSiWY^Q(J zd5?dY3U>n?S}^)oN6poTM&|PuWtqD3V&unyBrABIhmTcUpofnlZ-)O0X*2n@IVbF! zn&%jpXPi#HC}TO#uZO{(M~YIse{jEu zRX=d#{$s8!eJ5c})vckMT+?S|S+k8L|^mBkx?1MR^nQ4eJIvuM%Zh_J9!WAvh#9^5LJW^Rrd-S9G!*8{a&H@*bUQJXr^({YVE zOTuZ}f^8R3D=;7oX^R}y2v-ICNrQKt@lMWZhyhY<;Kp%cdx-A6CiC?NM3pj z$kSj*ph$u04erUoo*Woc3mKDAZoUMxr$IM7R^jnLFaH1!o{;aefcpjXfbX=b#{1F9 zr{F{?T=0!3ENr41#7kmZupIb<2)@n)Mbot6S8wlD?3NPYOAKGmqJZwamoJh4Y`x=B z^U-ZoDO(d}hLGauy$Av`kl>EAW}O+5*IJF|L=UV(&UfF|?xfj%^(FGe)o_hY3ln|-mKOl= zBLIFP%!81-had3N0~bGJrRN6ODwI3cyK>-piZIXtAQ935U3Y0eTcCI&N7c6>{DDL5 z5mOLL_@L}|?3NtS@S-SC_kCy0^aU*JCVZh{rF>%)IcZiis*b}ecgohe6ny4uHPGNq zz{sH8`v7{r0Q5Woh=J>Zn#O=JMb|X~^n*6*CggmYMIuZT@I^ELUow0l2g8YOXF@OV zBNy|wbZf4nT}RGi__Ee52Q9W2sj;q>MmUZ|)9j#8G`)4+7sLRRE9RmwIv(pL{Z4%{t+ zUT20XuGZ>JKfENEsiLw5h(f-u*;vcW2EL+$eANMk20gB|EtqlC|i$@Ga47>xW-8>ywYtO zW@x;#4!{90K~#5PyKk-LuC+Lwak$tQ{o7t35qAJeHpqt4z=qXiur?H7aK?gj)i`oe z4+Mz~f{HZ8425AtLK)GB*K!eH=OPZT;3&Vg3JU{(-3Pek9{@MR;bpOEyQF4Y5DmG> zaGMhN8@=mqDKyT7tI23iOiS(Bwhk7CPl@rRJdkPoVK(MKg6M$J`uh$ig&gh#iYKzN z^fJz40=R|2`8AZ1P->x<>(I@(c#UIWco!Sv!M%+J>Avqb-72)3{hsY0*2q1V8*Z2) z@!{e?LVDx<24cUs8+)AMt&rk1d#Rj)H#uwRK5|rT4^+G8jK^U+6!;jA&YG)O7(O-7 zds2|uP=NvH-gOx%$k5N-`*!0!=#J@lD1po9iv3)|m}cQ&j+`{w!-n&2NlU?H3i8_? zbUZBZ^&o41x%<0egPa!&h5JuX{>Ch>xNHHB{fQRfu|Lsb17RAVr3ha?!G>=SE%4Q~ z-SqOs#aj=`s;rG&w8266Gv(mF%Td$c<>)XH?>Ei8as+(6X}G8P-^c%?dC4jprtEuOYbKM#9_E%1eFu03hZN+YS--F0c+b!N`NSQnlR%P$JK^n zyyA->BDpH~LW+y{ZifD@qknoG&mv?y1QvV9-pvwjfHnyDt2cMOhTMzuzSkKrW;m~d zl3$J?Zp6rdg(JbjbbA%Nss<0VzP$);dO-C2tfK3U&{s!;E z%F?@3vh4|gT!Wmx2YqH71)x6casVFa3z=yEcwk2cn7E{39mhSp zKErVj7fy4ijZFC=j8Vg51#dOL%I|=o*Nukp^&eNZ0e&dqdprzvkf0bt)SbRZ-O!5O zNT@hKeHe~+6ZY#Ehy{*#@kF|p;WyD-c$>rI4j3^3 zGlX{l=v|Qeg#uU4L5A&O-){pCdGt5(EPRs(c@XMka6LHGbKi%WAAF^G3dJ4_$Yh3J zg%S>OrZ`f#bWf!5ck?PR#{9dD2U9%6tALx~kM0BC#h4-qBe`fcqG|A*9$-X^28m6A zz1yw5q-g^I0L{nmYzH+mYg@1ewCx1Hdwvvc4b;F2lFWAXJef&u?_lXSGdVdGjiZ5r? zLN%?q3pw43?gYKt<=t)*G)ws)PE1gH;Ix;-m7Z9bHb6gB`Irs(F|`0N)YHZZLELr7 zbI?lx5(P3K|8`}@K)->&`ya0SH`nGU=v}69M#0-J2QT} zWRen%rlr}gt=;^pg^@)MGBsf!lGMvusQAAad-HfGzxRJ!skCdcRASnM6e&_+CKW;@ zdX=(GQAv^{+1*7bVv<&3l2D0>NM)JqZ6bt_v1ZSVWehWO_r30WM$7y2_&pxKKU!wy z+~-{D^SaKt&N=sa%2>x)65Qjy|7rd+$JIU6>#sc^tj}+K1LVq)dd^P-tXGWr9M}EK z)b#ojSdr?a8^Y8pE6ta8izLw&6HD$Y zy=`7PzQmR|QeiG9Q~9>vUL3usye(v?Y-O9+#gq)?>Gmx7Hy>r6?dt7#pFe#P;leY` z5_)iGZP9ad-aCYCA-;NFWS6_1-s<}1@{(U7!FK2gb&|0s!ih5B*pTMJ;^k2?ZyIDK zS0A>+P7|%~8PSg5fq^Z|KB!R@&^dEdVHweYrz#$d46CW4qM(nWFK3|w?jEh!V5K1V zVLeUw1Nc;73xhvf`IpE=NMKp&R(@q{t=tT!)P<-tQb-?P1Vc>%n`wol$=wIa$#GXn z%q3)WMQHE~-|${1mHHOa#19DmLnQVfqy-xn0EVeEczV*}C%Cdd>i6W06d(ly9QR)$ zJ7x-hA~3U2S*VK?0o|IvMCNbv)~x%Uv0c0Wi z?PJ>a{)7fA!XJJAv9u$7LKZgNzth7xKa`NG%>XJApv8vyh!3 zCmEqIC&r?4LjM0Yi~>3EZ~+N=yvTM=YjS$@kIZ4Aq6koyiSssHNXgVbhFwmBetk2g zlz{0QT;}2nge8F#u&{Oz-FUa4Xny4ZY?IrVi#3Ea)dL^uBGSATBurrD5ap1Hx1bqk zboE`Z3w!UEVVU_8BZO-zrSG`1O^U^sApL-*j|9QcSbCO)(R@{? zR4ZURyBHtZxsW!#cp>yS!F2;>pA$WXh5|P^rZ2IvshHsYXK-k`SvYu1F+MnEX(|Jl z+yCKP;BE^9d{2UAKLj-5%AOFM!M~5~19^W3dC$OU2WOg)Hyz^*jO4wLxqU=~x}RzK z%7Gw_Z-3Jc5a0}Q#hJt8s`%<0vD7_84I_|&5eO5xi-Q>4#JAaF3TOjWV;DCTD6A1m z5eym#6c@mmfG-6BYE}G2V0KHVz}xZekOG0C|6*9E6am9R>js8#GK6x%`C#cQV;J!d zAC&(i`hOT94{rd9Fbl)foQ>hmgs5iW$_v3fRbWw91)u;uGB9P@f(HtGI=avOZo-OJ zB+NDc{v}>$n|CHmZY~I${pBUrk^w$E(F5MDe0&k4LpV;KlwJu?f3o;20^0glhJW*n z$*{@xf0T?z0HmNFcb27yK=^tSrv112F|dVgS-;&%8!%cLcPj}zbhv|U|8^^ZM}xPh z3lUF6P8ejwg+b;w@t}bg%&%~i2ER=B|c2pbZ>8SY*a zPwEvzV8{l%{}W*au!KigVQ9wPt6D&&6X-mLD1`A@{|Cmgm{Q!=Q8#b_tVmUuO&lR` z@RpD<5Wq9ni}R*pcA4Fz+nqBdt4Do)hNsr0dR#A2qvHm@b=g>{3Afqw_5ftJ#~491%Uzsl zx=ZO}EmM8Erf9Emb}!l8!+UQAY{4TN7e6AfI_4r5=#7$b{Al~8&kU4LBkAXViHtE} z{zF$rCFtJ{5{B9wVHXWl9V(E+$VU!UEP%9WR8XNMUU`Wwk)vQ(@u{_F#JRbT9V(RZ!_x`jBjq^PY=RvS`k)MFF z7taigwVb)ba5#kRM&XS$AdG~h^Q33=4xY)yEUxJfZ^DN>6fIAOnztpwWoP*Mze7Hz z(D_^o71d{XjH^u0q1_m?GiUq~Ir?J2$r%`{iR_ai5B1{zy;VALhesE*(;w$@xx{xP z8CfKDnFHyC`Vh>gF!E1|<9$huYesQLxvC~GnhaS$)xj8nR6CG@i{pj;9O@)zb!Xzp z=m6U~*il*7=(vz{n2f56KO+KJQbYPf17rlThq-ZiLKc7A!lbX4FgA=y)Nz~daW=*u z)k~A=#pU)%>GZFo57bv8_7FgZI)%Cs($uEkHbD0KC1UT;hFbL_(2Vb2i27m=R1gkf zdXX({3M*~OL%CCfdE=G{BQw5FiZImegh}G!_(z~wWI)|nW3;;}17r9Ct}jYoulU#y zW)q-bu^M>q24|LMLX+bFqmK(e;F{Nco(7UIb_Tgy5ubB0t1FY~g%-V{!hTMopPxe$ zfeQDwjNEBp5hpYBhj4-qA>}a`=cE^XNM|K(zWY>#s{N9e$45U4yPr@$PW%HRDEkiH z%{VAyYiTBkk844Gei$jo6|XLyLc+|$ox4Pn`^P+tG4r4wc`;!rLZh7nTX8gTD_Y`v zhd15;+xRk*e1ob`-v=-QmkND=3y8|)KW2~-KK6YIoL#D~^!5KVl8M>L$yca=Adw*@ z_gV(^TMcQb6O-+25FtS*DO`kusKQ(CE(X~TInfPz>=5b^oPjR%1v7zh$c<|*;SO;( z?gd&WOy~?|X98Ce=xowYOlO_!GgSCtLTBH#P@fcJ00LRyWSsCx1M1o3xxQok7+6p! zkD>9$$;^Z$Zo!VA5_ZNu zgD^ki@MHGM_bBd0QMlJ?{vT-ygeLUbGnh07{z&tW<+3xxY6xKd;-2xIfNw9(57h_; zFy-G%LdwH%nLZHMzjwE0Erb3o%ALol2dKgcS05N-{q`fQqgie;Wgy6yqxD!n>j>Z2 zr2p|oKwB=KioqfXy4%4oe?sOCp}j;hNQi|i1KLdd0Ln-s4dQkOK3#?3&>2`)yrnW= zH)hTV*n@eYG5~2t(q7D|aP6NYSm3bDfTLeX8ZQ}hZB-!z8M9}pj*VntXrzB>gr-`= z5pz%DJ^tQ@tl@I%4#&Q{-HCon0n*7s-8hbh3GiK%URU{(O}gdFWzSk(i8*zOYMm3Q zvtAs`ZNlZ6N(U1deK?d5go79hS%I2!|H)SZ{L}uR{Q&@ZQz7cpPseRq4Cg}&M^(Mj zkzhcRNkfVPBfy|h=u%1$H%OhI!Ftyz2jjXE^OXU^1bH1Hb>OC^TDO+|+rDw5Ya76T z6!G;h6@cd#_JmnZ5)9OM63}m;ub%|u2wY4-U@jA0If4GT9sO}vO5gWCk4zFkV3VM) zzkc|uFNijR_$Dyit$+Ae{T&1+P;ip4C$1bD^GOH#w>RK5P{zfL?{~~yk6Gp4zmQ&> zo(R+X1r9EK&)}{v4&HJ#7r^R}f;(K|N00^hXeD?!9w)|bI!yk29MV=kZ&)^Lme0rLLz~dzmQ#u)B{U?CS-0C@lD+;(q9whvxgS@rsg5i4;WjLD~8Trw^aX8UFnSnBSfmj zFnN;CYUYKkmO{@bUA^ihC-yZthELNHwa$G0B7UyJ#&-#KE0T%33ds>eblxfp=;Cfk z94uL?Vl|8Fz4T#eI;4G&;x8G0=Oe-Ki%0dkC^d&koTvMlCM`p5%s%qvO4!fw9@&`O zP=%Vj8`DG==pbmo)?johiSq?^xXVEgx-pQ|Pp0x5dlxbdT3C=hdy)otR9KQ{KJp_V z6}bdHER13cyoegt3;Ey!*7VPVP!nEWOYc&946}y)P&M?m2Tknw-4h+}i3mMSLYOPa zP^h@e&n0ybcVmY)$WQ_Jj4@?`RcQ@q;ZdI-l5lC|0W<_IXO5zQK+>fRSgnQ5d_)8s zsmLQSSL6M7W8~b|-qSk2%CefyR01Kx=?dz6%2@a*GDiZAzLF0i1=l&=zeKi=19dxr z76qOXA(%d_s)|m5`A)IvkoYq*bbp69$H+$ygi!`xf-p`3aY;p_;ibZE^HNDu{IIce z=$!cqQ1LRvc^u%+`Uuo5fK_Ak=tv0pgAYWu875bdt}RaxTo?rAEssz%AnFb#^4hOd zW;_Zr-5lV+1mFIGFLIGZ(I!YWTOW@F*C-)MgGoGjzZD>vAMpaoP?Pt)&yA~_eKALrlw zWTO&r;Cx)V6rBPb;oE6;z%s?GHjn}=YGD**CGe6yz(Ge&02<&$nXnwqE2J*X-x{~_ zn~qPQe30gyU^%#qsl%$`yy=+XBn^o>8;_aXg!8v7Sl_!lK@OdH(*rtx%gIG6QM)(z(2$`NShlMD5>e|HXy37CU_zh-fx4l<3F~w~4b%*A zK@EvJ8IK_=!ETJT^^qSs6QTfpW8?`suB`zd!j?Pp=%XkM58GuBOxm^oNS7Wl7|fF= zVv3qjI8tz+Rjyw6Nn-?=7@Z;zC=`D1ekQc`TfS>p(tI&DRo+a51xG6B^TA-<%_eLH zbp7{J`~0T+V3S^<&Is$-!}ObD2IvCXeB{qlq!vM+1guY5GSXszKZN`eS$zz%4{%Zf zb4ci<;08X$xaHjuTJTRuI|ROM-bw;J3B3~Ps09>UPrpRa-S08={{Dso^j`gA!&px% zK{R+z&KOEyJ&A*VOJV*k=*b;4jy;FjJ_*k5YYF(;jTylIyKxYazu7bkw(;wPP4q1{l62*Wbf2o5&bNoZXFja&l(g7!dN6kH3Ns@o7a z3o)FSuwrrEj62vSmLGCWcLu3oOa-Qx;hqv0E}Ys#as3O#g=rj6>W}e5r!x&Ozf2aQ zjZa}iCAz;I#xvyYz$o|wTYnRnM+5z=#Pri4lq#uZmyZre#}lv^cZj?+%r!|Z3M?^P z90Jp!%mdSL{cSpQAxr=Z0$9MY`LAw?cH_lD0mT=Qf5RrAG41~tAr3gf=oC!t7-J-i zu|nus2!TStxyb?Ce1qfW7XVfBEA%ccA*lLVrbexntQBcM+9H(+2<-KVfu0=YS6j0Nt0fJaFPX1^U& zh*p?`s{R`sOos?HifkO$|Bl)iPndU<{p+7tp!{E4r|@w7Ck#o~fO9J0y24aG5vvgJ zSMl*VzXJ`HR$y^v0TLp4 zoUkKd9LHq*Z+Q4W_V@2|WR4lOzWJNWKky|``2>6k#q%fX{ri|u$bVv4N?JMlX5H2CHF8If&(Mwm5phr2O(78`98{YH`R= zIT-55(Hjm`lbB%eC3)#Ez7m#@zJpnaAVE&R^U*A6$dEDPj{l*GC6nz8j-dwZqnmw- zz*zu63ef${FA@GUH$f1EWr!9d9tOgv2wYfTgeb8)y1BfN(-IL`xUa+XuHX3HLVgcf z&G*DDbYVNIHOxm&Ll|P9w2ccN;uZ-1*~@(|(!(!ZA>5-q)t=9E&tH;tN!=Qz5H3s0S1LGp9z)U2z z(bK?3hcu*0!#)CU5785ZLkT=cR@`~3qA+%Tce2O(PbXr{?uAYDkmcbqdat z_B&~MR*90|je*AYATP5ZdBAgIEx0=4-*^M*tusaocqJy+1cGQDmVApqbf#k=eY{My zgGYgcQt?j^2lD_+v`fsM2ojJCL(uHPAWWQ}12$f4M(`(#BVE=eyy*gUk?`Cf5Y=a= zSFZrFAf+@FS|y%fm?H&|9AEJCK7=zL(-m|y(-^p#l_s1~=x7PDb}WheZNT_^X8%7O zL6o?GV}=ml#hNLFjB)AxC?xHI1Q$>K!P)&*$!Z8wQBe3=mI7Za6IVDb8R9o?I&P5A z;)%Z*>3=xFV#LbU@&!nR_eA_Q;TZ7%0(JXMzymOB9}wV!4Ot)v43r7~Otplw8IUQ= zW(0xP65kN|S5&V3N*By#Cgx**a^{7YpbS0{(+nWD0CQif%7R))xS0K^S0d-@f`NCf?>lEfl z8?eYSfzgAYDBNz;d~G55QbGz2V<}{hAccf-cSW5 zVDQOrB8#*9D;Wg@Ygz>ehJx5GIingQ&cf_MB}q8h{JY}?c<{s0Wz}{cOwjgM#jSr! z1ytsvKVg%#U!i=CPmU%i0HVRR!3dvV385g2Vi_UKM+|+odG&hz&YM(WqNXw7X}(AQ z&vR743q0-3UP4@vM&v3t*M(M}R4;C6WvDpLrUUBvKpK3SG zn{>lorD*Q`sFCH(-{%oHLt^MOMw^x9wc%dtjfW4djhnA^HY8Y_yp#6x@(F<5^T?VJdSEB2*yv?NAEvD?{Ta#s z!b`5nTO`hTWQpdH$7YVc5N}r9-^NrO{UzdAV`a6&@yyWo-Pa2jH4g5|KVa}=b+o;& z!($8iuYuK?2M1!(3tGNDKYP|d*6}Xqi8GrL_=b1vnD5Q|Ud;h~W##4z;`#jPldfHL z{Uw4}ivt)jn6)9kEJSY`4Quq+AS5Cp=ptDe*>+_ zP~pJQktwyG=nK!Rs75!|og#m;NQusipS@1L-O~1^ev9t4wpH^3EQm^9RNFXTTb&Gj z7HRL7j8FLF?{LrV>V?T0#O74}yg%G+`lM=!yCEZP_*TkDLf`Se)VSB%&RQsmiulf5 zlNjGBD`S}LU;E$J(|w(3W_Xo29-$%*?<>&tss-NqSq=@H(RbQ;x$5 z#`kxu`tKGJcYL1Bt<|zT+j-wMgKpm&dWreTqAbzy#O+a)1?J8peI}n=s*kYBHh7w^ zEC0_s``8;}``1_PBjs19h-&(Y?cZ-6aO$ARajw^BeADJeN9-A#j2d{ZP$_2BTI-g-F5cm409fdT5mFALygI-KXm|L7VU;w|9}B6be( z;q{3hw|_CjyTQ5=ooTWAORny+H~w4wz4obZy%Bic^|G5?-`mR8OIHnz4Rx2pNyf=v zc5SWNSrHov80;G|lc2Ze`o~*G3agiX2@x?evM`z<9N`j1)5Itk8E_QRRxo_H^T+~m zw#?Xnx0W(k1FGCG-s2^l2&T+05n3dFh}YXs4=jT@Y)~{B#}a>Mn=)n(*EQoN3~{=42e@*bTfgQ)I+~cv_ zPTRZW`!kQla{f``$Cbai>8!Y3L-5ZGrO)$_G5DG}f6?pQ48uo*LDH-2FV(;7zLzWO zf9d_R?+Ceyw=ur#spCRVsq1atfot{mZWT}Qq+ii?dvc1XP;;I-`;^7ybj!m#+>%~~ zI!J!lwfNl5gi_fw|INgV=;wN_I^tIGl0WEkP$h@@nmh3hOPVsW@)WWSHX2C2P`ItD z;MlV5pokrlW)!D&YxApYHN}VFxAb=_xmfl85~290CiHAPbZW`h%-rfJGgh3_HQPpv zy$t6i(sSTw(+)|v!3#FVs@3%<7P}HAzJ&YIAn`z@$N{i_<^@#$V2SU9maM*F@i~YE z={)>N>JL~LN2SaIpyYo68HJcQb8T^4RqGwekC1G zadmfi>nSy>Qr=qHG^C>VIG7~?LOFBMwW#_fvfO6pmLSro^w`Xi@<95a5{d6i8k8LPVLUpkn$suFLWjsD z<4!fSW?!4ay_ZegTu#52IPU+`u0i3Fm3aV9q0M(;bDx)NN?Be+s^zdC0{l}-2s_%JiDJCY? zGsg!M|J}sWidkltPhO;b^hp;RRlJekw^pU?e%a!yTf}Y`4DQ`nYD7==Ahm{vvIyiF zZHbo~5BC(i^Aisgio9BEc5eEQ+#p}?T`%8o0xlYq&e7=FiFfTHLVPZ1IlN>2fi|TY+t=vwXI( z5K6}DW0mK#t!0d=r94iAxA?rDw|*=-@9b9FTz{El@5eh|z9`jp`qFmxExIDv_?g4? zQ!|bd;~iw%u1kIIG+k+*C=D_0{W%{vhHtZpnN`$4y>h*`Ns3<8@%)8|#o@*e+f&VF zA9nFK(e6xuDysN-%EIpYb#<(Wbnday8+)%F^V2(+PvWp0A4l$g9vJe`_w==-*-MU3 z@yk@-Z=h|wcEO{xtncTKd_d;!?YnANUwWe#ozIF*V9|E7tn*@$*2P9iO&_)KsWiC# zasIV{Avxl$Uf;5H@}~C_I~<3lZiFZyPB&6=(Z??FEtZ&i`QaUjnm4?~VXj94as_hJc=yRCV;oCX(lWKm}M8i#o& zVfTTGvW-$jaIKZMJYX zs`4y-cc2C7NY|_0y6(o#6rTR30As`5MMjDb{kIEv#t!RaeE)l-K5^H^g%k)_OMEw& zjF=&>7#}Y2ANfpG<@tacTgyOLLT2d`B{Su4JTdafC<_)<$G@b*^u5PV%cS+mMAGSe^I_-@R5 z_vC}UT!3U3X&x%sz}r?m{PA0+=lL=9!3$F^?jrmUi#15Nu(c#4syx^^wT>Btzv0&W>geo_C4|#U!sG9anLHGp!_gtUPt;(Up(knYbeYi^I)vT$F`q#e|ev?HjT^#wm7$1Txkdu4wH z-=gPdy^I5IgsZgA*hx9ymE8K1udTW*_%j)^RpLOfnr}R+Q>hECTg^UVekf8;#pj7B ztJYC8WKfTPmnVBohJTEEFP^~N`^IF7&m!jNC5@!7>Y>ryohL11vo@?$oDvW#;aaSG z|HWnNdZf0=nB{8trq*xqsh1W$b94%qxrGr~^>3M4v0L3!6m)frRCwWfYm!^HurD~~dZua}5pEt8pRf`BS&J!d#K?4U^Q$}n3TUT9m zn$oc1vg)2}eb@W3Ca!zx{u`K5)#F)Sn5$4k7x$C5wm7v_K9IMyue+1+ZO;#l+pT?* zbhh7^t1G&BX>CsHYj|_~`U)RWH(!^QUm}@7c{9^j4T&9?xp)0~9TTfs%d}jj(ob$O zkrl_~H^+OKIjy8g8fY1SH!UdVS;aV_@bW*AQmNNok*y^(H|b(0-{m)_SY8yFIhUxH zx`TU;i+Uq%{x1)h9n@;m->Vd3FL%?W+ltEWfK@IwJULZ?{e29a8&>GMAS~0I=5rUz zUJy%IYQCJG1=SOh7&=CPjbt#h zRDz$Q*SG4zQq$sde}9WOF<_?*OrYV6jv4!%&gF1=$mUcM_YBll{KWZ#ifBC@&LVZ9 zV-nuS{nFdE$3P)jPeeLp?RO?(U%982|7PX|Ny6xA>8Zyw!@!KIq$fgv2@9+pky0Xk`;tl1@yqNua*O2 z)4n6M(&&E%u2BZ%b^|kqpddP^roeZx7>*n5E%RHByep!P6gxJQBBDRHoTHBhcAX2W zxn32WqF!50HB)@DvX?{YG!5}WOnKcY@9p1+kEkK9=1^yeGYC1+52plrq$Kekl(&6&o7%dsltdfsBCW7 zma?h$5L4RDUGW|EZSs&DRsrF%(`l+62+qwsvU9D9q zKBCM~UDl?QCmvNrS$CoWx$m{NIz8aGd#CHW+}PG16CXaJLT_e-64hA5ORlY!Ivd|r z{xs9OQS;xnX(MZk&b-$?FPYTJn8Dkf&WU@|*9C45)v zv!aX~rs=z^f_CM)GV787rkoq9tm zVn};b6>7ez4N}kDI!BJL;2r9iapG8`CbD?*+wKtc<%jp0WvVc6-N!{0LQCxP=VVTor!DENhHyA8# zAOC7_^ngR5YbJ!CEju5E3^E|wlW-#kyGQNzvW|)Q(DW!#_pHpaCss%Nb@r&0sGRFC zcv9&`gF`S$+Qx7qP)8Bn0E@u2{KTBy2Jhn?jC>IfgncUdg>&+OJ_}AUOQAS#5$BF~ z(n*U?w`&|{tE5daleoD!f2BqtC5#T&SA1GPcxH%7R(28RRioNHURhTLMzowZc*rTr zDK@WtLUd~)-i?iN+-N%(JL#e81qC;`SShI)cRl zY911|a;|)L%eCT5(hEX2ZaLcEzUL6vz#(3eb(lpfk{ho{Ck@2$m9r}7Cw-j@>$SI@ zhalkcO4(Vdc#dVZnZt zYKuGkSyEJv1cSFnIdbGw3?*KXcAwtzIFmFk*-v7wgN^AV{FBr=!6y|}5Wnx@ZM|ha z-M>WU=)oFR1bjQI!n)LG`-=&WQ@7p^Cu29UA=gDSLCjahoQ^X~go~5!RH4 zt6oLy^E507+Pt`U8(k)Exhn6|T)*d~sAO6*)gKmq<_$~Nw$-Hc-Eh1o{n2CAb=}VU z6pJp{OZ=G4(xJ7TWPpUVmOj?2KgbOypwg5g)p2nGmqp+lq+cek_kcK+7kbn^^s71U~!j+B^a=oUfyO?9JEI2jhC57A9nU zyQf|FLs2BAajwH76O9=sQ;;3qE%#mZe9D1Wo!0rkMAomyFX$d)E6} z?BF|C{TR>OTUzzstya=3RJ|A7%xd4dDem~usTtQlu3U5=YjSdgze$RB;Ks!T`z~Cs zS2Nbzuy#|(1tqm@&*UXuJ$j&PXsjn9zi#4+C5e6O6UyX|dejyx-0Dj?iY4GG~8q`6V*FXeUzJ zLg21D(aXpPta%Y<)BU8S&Z)R@-Hgb7y^x?qpEp%!NAqox?56vDk<$j&N{hpH^|DP- zjm~j2+q>2JT<5{Bi=%FJ}zEIs*k*s7D@&wJ8WL%6no zjjw^~_&rjibH}#YBFaSuzVPEy+d!Q|YQF>dbv{f3x>n?^L`Eu+yszxeLh_hAc6Ipk z^Q7_V35~;Pq+>$^^~U?@RXLjR#29balO_FGi&h`|J~*2HBhQnl%$l)fD?1VChsg&G zu*+f2rcpCy$@M6=Tg8o`9>uqtq^@7edLrUN-a?(*d-VBvr=0|obil(s4iCB%&z&;T zhP^d!Ye#f{i8$W?oJ9((TX!SxkpEz{|28$NPhlFW+6c*8k*Y{94ixoIfn+xkjhX3d3V0app=qu*Z zSJ<^eMkn_Mee9QY0|`^-Bo~RLzJ`*46}8P2oKh=Ad@P^`j%g@h#f#}bGa(*?LCJU$ zES}9=Ti7^AfW_-gx!4X1tcKhUGb8bI09Ec}hr&Tn*AS zAM(44G*sen@ay(vtZC^Ct`T%EF=8M|Hg8CvyM<4Fr-sz?+6J6HZ9$`@->#OUdAeYq%2(6KY6Zczc}T z4I3Yqodmg(o*@;haj6`G!Ax7e9~-XJfMYn3JjLg);~UEoQV1Lajkp`zZlwKUl+afz#2V$|4BkHJhYd@*Szo`pWNDSfTL^D0KcoR-^UF=?pYVR~;j z{W?wFG}MFMNN!iIK_w}igyW>)Va9vME?2^++aPh{6mWLp5G^}9EA7SYp21`O)9;+W zv8(QY+@or*3vu>OyID5fS*G7Djb<1=box-Yc{9n>s=WBtIwrM97wIgcwCg^jUs{*l z+;mMx8-OFiBF{VSXL8SH_Td)8ohIsz%NI}oJgKzuMJmtaLHCfldHv5A=N0!QZud)G z8eeF$rEPUpCcU0uMA;7vJGsnxIu>!Fsoj2ac^a{~xpqfe10lF+{z84K__RzfW^{1) z=XdEPkFGCn6n(xxykmbw&HTzy9i#dmvp$}Gl@Y6TWz}Ls+p`}S+c&FszIhp6dadSpdS@96ojNK}?T4W!&q!N_ z*D1NJD)A}auJ2L4Xq;dn^(;ZE`lj?!G00B<>DZB0T-N9M>g_f4Af ztr|XP8mv`We8|gxYb}NIbEv>(M)g2HEK~$;J(KKgCt=oP<7qlI_)~ZOcJB+LWXRVIrT?iG<089LN9l6dvW+yky(6d^>oUUBS1>MtWn9;bhaq;2M#AUX-M2^+Ii`C?~w7&LnepYVR!r$InWBko#i`~WR%`eX> z_r4KfKd8TDZul~jxSB90=Y*Gs9fr6klEi~-G<398pCZj_w3kY!PCJi$yFgR`Ngi!O z#wFe0)Sx<2Kx5JQGvC0``z2hP+o58$@^zg1JT=y<-WF?1@O+DC@apoCZ(x!80Y=_x z!bk3jYoaxw;=MQeJUjDcpJL!|JwLuamb?DwMDyG9g44AL#H!<=sBF!ISAu23LxqU@J;YbdYsl9cys;S4}&J^->_!I{u1RwuTp;qFIj z!ZSF^s&$X6#MY4t8KQ8=RM-ljss;#e2nUpRu%PhH?0(WnNVrdJ(JSps`W71zV$|ug zvaMgVRP8${_>BC03&{lofsqcU+h{gHZ?>LrQtvBzc>4w{?I}|@)HY?xWDm8GXf2P_ z6NlTb+TPK!bm>gWT>T;BoWqLI@SMX0f9;j7sb!~N0qLQqBG>rLk*%mkOYCOOn0+f_ z>M5@&782|fkC5bzdl#uJ)m$m}HKL6ct{J`WG-wgzswZ(k_LB8%o5`$WtmOQbGBdp+)0I!Q&+{Hm^+AldZANW+X>zx}PMizNp)_}nMERyijU6s~ z+Q zB6i8wJG!icw~`HIj9yAdSgD^nduZk4ZR4%!PaKx$9H1ns57e9Qu68r_)@}Lts;ub! zf~?r2sds0$$&K{iVyfKn=0_)gBcC23eso#duraLR&{BIQ&Eq9M@#lcsqIFe;`$}GX ziukFy>iVKf_nk(Q(h4obpSBxRsGCu9^-PQ8<<~8LaQ#uj!%H*t)=7xm%=qiNR6R|e zH`udP!`PDB52NowTAk{|3lqs(4+g3_ zWGC$9E;lS&=v*;9NFOS7v<-H+@B4aM{qBuDd(o!%t9-9ieONiW?(;Mgn>Dcg9F?)j zTTvxe(@!eNNn*$Nc&Hlgs9@Ot5?M-WBX6*cka+yMWRy4vTX*P%kKlFI(7WhDZ1a%{ z6U_Hs=xzX)B1pP8J7=D&xS{Uh&KT#GX9tH2i&l}VDE!-Ba{^lkb4w0y@vZ8WyQ zGa`)C>tFkbLbq{(%V70k6G*DEO_LVLzwFj8ksQ?>H_v2LnViWeBolpiwV0SN6K8tu z-}&PEMwCL}hVlZv7zKIS@(Q_liEx+LxH|c#>Y!vVGK=265438c$_w_phOy%25v0$GAEsOw0-Rax)7qS+7dReLN z|KIkaTPI2k_E*K;>iQ8K!kpjls&!~EW~BiqpO})E->PG-=ewrB_WgS?FDbt|&g_iT7I$o8JBbpu&4e1G3myRiApmX#H?PaN_HmFf5rT4`VOHkKQ|f;wIh%(f?EFY;V;)2tGEYb8|o zj16~9h6;vQU&Gk+*v#dZ-kjeWq1{ zulqZW^zWC@kY9YPSAzG-ppv7tk~fugTFHz~;P({*hNV%{-*>sqx* zuk0QYSTwi9%d;wMV-8fbKT+}AGGmuRb(LKrS4Zz$UT zjglk2oBBCtV-d12$Fj9dy?Y!@W@m5jLCwFl>b^QpS`%PHg?8D+1J|t7&Iem@PH@F)W6qOE@jpI=40d9dEeCA-ub4y+8X{!+ovQq8C_hOPadkp zlHLf&-fHiop9)bGxrARLM-t(-{LoD5I#M-yEh| zYGJi$$(Q@Ov-8efAv>(Qb`Dw6TH4pvobKn~Mk;{%j#r72-qaG;kaYVSd$^l9t9E`$ z@A#}0gq(af_XFYmN%__H2wm}?dVNJam#F`bmu{dMpn7l8!#W6W_K&-3Q zJ$>;Rm9@)m!;-MK`YFS<>L|`O_wgm%tYafo-E-?y-o~;O{trj@xuuYd^l6mJsxAy=lgyvUdyY@rc25_VHF%=N78`CB2)PM>upJLt^nsJGoM zA6MvfIx`d8ZIzye69?eCsoVip(;-l*4eet#eVI`r!V5@Br3Y*MR332 zGk4~9N{beVT$QJ>`ni|KxsR}kH;ZHHIqP;3wfUs@w;;F}<_f}`jqS{2an+zWR#7f^ zJ{_|1$0O8n>9xoJSI~pp3xI+S3Lo|lGLt;T)|rsrRuf)Gmh)#bA;DOV9kw97kge-( zJ&DLbv@1Sn4x?r^6uu;l^67A5;FOLt8rVSK0u3z&>H!!Du&`0M!3IVxa|VP-!L}Du zzC{huuO0z+*pKx==4r@fVdDnFxL(-OI}Kn$i-|sd!NyxJZuIVX0PZI*@u1wJu`*BwThje#p+53$bQ{0AM3#TRaif6i4R zaW&NaK5F{%OvTa31a!?)dcST;@_i4lLfID^E0IFeUO4dtl#h;eIo*su_#K%%z}rw< z%AaG3G=r^Rhs}Zx!T!a#r>eZkpcpgw9A5)zgbgHg^l}3sM#_23;Vq1-ja+mOtyZ7}`MRm|l=d?&L@# zEw=$J;!;W2h}Hz=$8+v13#55IkkfOQ|9B)El}Y2N5O_*$?D*y*^SCP2|>;bLpb5l;=}z92=APNts(<^}X<*<7=ZEXRJmR z4b$dC@ZK*jmkD>-W1X_+$rIWYc(=~33T!_~MFrA+tcuh-NZ`+L9N0ffsmYsBL2tLM zLVAA^pjg{fI=!TWFZ?gSD{(3~X)8qV%ujF!G=p4J*o0 z+h`h`0LaTQmzJbC%R*|`@c}OFmyY|8sb1BPvLVlBJfa|$-m+T)DjB30_0`^wNnOv8 zS`Bo2t|MHY7P6Mq-DA?O{9cUbtqW6&JFvrw8kmGCZ9#hbVZu;baf0v`in6dzdo(6h zNo`*v!{Trs_jvUt^k{wT=}Vdf-N>?yT=P9JrwB^|gCw(PRGnxkmu*iO^s0prc3sSlJb3rTZw#G1dmXgDqCJYMaRaWo-!?)pNpfIafA zTWakmlYF^TD zaL^g3dc1j+_#UHAa7A(fs9{Q`uknAjPhmFFO&^}00shkqOU&4Zd9VhKeVCpZqILku zJkJ=P4%bJ3-j|Rv&o_;SJ@_T^5`LZFr3E@}+Yj;Y~gD z{j=&D^|l81+n%i>1sd+29ED|Wvzes&i%1;DkHXAYJ5&f%H>h*5*+y$Pj*7Gtdm zKfMy1(|cMobUca)IRoEyHD4jXr0@(bgox~g@VRgALq8_AFruD4WJ+(6?)mOY}Hk< z5?XL6?MfVhT?UH-cTi~)I7_ss1vKD{O0wd5_15kECGxcJHQSu0LJMXLuP;LSArTKW zwr2&u%^GEXv*^7tRKB8g!F1{m+p}UO7Mzl-oaxzl%Q+r$<1r9`-ud6#P^i1Q{PmkJ zA!h4c40pFYziAd#$O^tfYLR66C8T;zZtGL?j5YMl9ur;MDeGY6u&FQX$+RPa5~S=X z?=tLs1(WE~&t;p`Us@u)qve9x2YtOJmr`!#P+z6z3+>?KG&|1y3a`yx=ltDeV2j<> zsj_HLUN_U3cO{kp<-6lqXov;p5VC`Oo}-EGB#HkLsZ(kAC8D=Z<8^T;$MmH`M&gaf zLj^EZ(f$2O9bw(qvvC0DW03XD91F=C zuJzH3=iF#oq|r~5>57Z|wDayUWxK`2$0$K^(|e)PmIprNHLlu z<~0-M_(T#ekNAut5YpW&<{Sw)mj7lgkF<$gAwbe(D;-at9+uy+y58!%` z4Z*I}VNiFT@_?8e(jr}nFz1j8!Y0`*{6-K*SA^@(w{ov|h~>A@0y8MQ$rPTF!9^e0 zhJtz$DpHC{Sc~@>r!hMg(O#Qe-cmva6qXf~%cC4my0 zwoQ`F_0eHEjxb+Fa1K8}Z!P4hGmYWX9ggKC-ec*SJ9e#SGn$ihNJd=UJSmUGZ#b4F zyp^RRiG<6LZVoBei9e*W9uPC-N=p`qW+$CGp_ANK!yz>*^tMEsyv^cNky`e6h@yef z&RhtbB|*U>uPzYPOS8K5p&^~KpA2g5vVa+M9s|3iB2a?~yS%X09M~~-KuSENFpU+f z^O&dH$G{rXyADHJI^;U|QEO*#0{*N`j8U)?)_;fKP06JthuG@yPA!0kmOVZsNOev$ zpeX!{-*Dk5Xb&kF3s%>ju7!7|+qIDku2W8NRZ)rBLOA3o3W}qz{YQoP7d-oAH;vmfnIn6i}8n%Wa(pyQSH-vwv!AobpWWh%&lsDnz-7ugwNT#Dxgz|S1QNEvd=tF)keOcE-j zG|0g#4(0`{|0UvX^O(~p%`I&@OU~fh6?)C?bzk}DeEX#Il~gi=0-dAr!lMYSE9$A zRH1Bh`#yaR@Bi`j=J8Os?cX>_N;Juqbt=i0BqYLAE)i*>M7F6^nk0#=!xSN+2~i19YfcB-QVZ=KEFS_>N7K+b3f1HeICpE5JLSv$Nsr6 zzAPpZZ^Ie|`~Dn5Ug|c#-xq%gFIiZzCJf~#c;k!oD}8S5WgU(zt}tuFxV>S8_s!pd z4fg)I3qR=>`)=U}&w)}<@(j8EJY9wrWTyl*oQvSR)ILMpI`Gr%-iXrVH2qx3CRkIJ z#;{ATB(a3^1Hg0xI}|E^xYN(oLvQC7)>w0&5ATX6OSt;amjdiCXiMqM@ZuRGc=0dT z-g^VbA7;@+cwQzEj$&N!WuK@RCU2Y}Yu&2ho_D+yKc_f~q;CXEN8otm1Wv#D<(n^a z!V9n~lt|n##;I@ced72ap8o292FCZ#t8bq9h{)VmT_NeidlCVqg0RS?!g=!i4EsN22Oo5~w+k=y!PvOAl=)y_Y~bWUt;aW}B;)%On=Yf$ zmylcig;_ItwsU}ummDj|R0bXe8S)?H#$6|HsOp!=1C5rjAE}u- z!kuMtXx2Ivwl4zj0J}@rwJtsOyQxcfaA88OULO;i1&%u9&63zYqIs2z{gU76V>FNp{AKnAH+ z!KJKEvE?IsxZoJA8Ogcm$L&|-FX<%@C(YWo;G~gHh3WWH_Uo^D1<(vH>41om-ekW# ze{ruJ^VHQQmc{vtdF>!93A?|V%NIJouF5cLn3%nbn|d|VP^@)7kRi6`ox2*^Unf%@ zJ9G3EwryeS*Ol%acCX^M*Xsr3jOC2nYJIBS_4tgbc3f+C0~a#|LdP4*G4ss>OR_i` zMxWKn#pEeBYzA-`W!WIC;>JFIH*qV=3Pl8EVED#A(w!=n{d3oE(uq||uMvzAelTH_ z9(U{aU7s}RAK+D{Mmg@Xv>w|h{Uz6rt8enEi-4EfiMD+XR&R^*&f5vTjvmE`TGP?C zg#lWVbH5U`goG}JZ}pMRofJn*ays@Swpe-jES6iUxV=4+*ZiU2^k(@|U4E>hn^~dZ z`T^rpt=-JcD5)ZE3VI{G1|3q~kXyHt2EZm|+0N`HDh-ncDS)y+}W ze01>rFptb*T>~`jOf{9EPvg%^ak;c$!cUGKDh!tUEvJRF?jKis`{K~d+qPE#VQz?} zS>Jr67xUhFOytTrO7rEoUFACtBs|i4{l4i4;dt~wb;YLa7xo$ri_VYn#>+PSZ!>%| zaq3MPy5=6A3JdNQeSFO6P#kid{`i)GFa93>+Gg}7x}0g_&74h{ao@yr<_dVXi|jol z(-WAOq2Y2z`YG)xMLLbTP-9fkyfZI;((Qy~s&@1jj_?aKdld@#QOEQ{9TneKJ=nI> zM?Kz?b{ph#Y}a&~JXf;I>-RK;854Ewvt(=*_G7kjv+ahxwtTMlMx1KqrS{F5L^_b~ zSJWRU&^5qh6IC>Fc0IY)8^bU-;C8}5_GpK)(398qcn>rA{aX5ZmjrY`8eb@MVG89^ zKTXeREE)#l2lZjSG6N>bbLKx}9*RHqvams}l@w6W;cj%5GvX=1kP$%8VMpSXCoWbCQnftKysLB7 zbG2UV?iYEK);C=#WkS)vo|bB5W4(E&m_COqc{wz`Wd{+(r!!@cj*X1_HF9Yi;_{QRyyJ+0Qn5Tzkc z(Da_Zk%b%xB?a$})pxkN6g*DV+CEmq*Eeey9isF zqJl^6)tmY^&F*$)SKGZ9@8x*^*V!=ik=L=|XAVe!NqZw?V#XpP@FscHWSDb3cbXBHiDw5Kewqp&&YC6DEaSZZ0v;DywHHP+ zEPnUER*MY!7wrvU*k~_4;~=2DnAz$dTZHCVNlPu^Gh|;#&1M;ZCTtYcaHLnY`0n=idWX4Kw8gj*jdn+BLqM+S z)wcDCPKWqHC8C5M8QNN?g!n5ztxDv{YTxJF++h>ZKM)@EGA(8RWvnMppy%2HgdmA2 z-J?6b@4_Op6D;F!ZIQNRatgAY0z#L+dON>N<>eQ6R-vRbaLNOF8l7`2 z$uqx%hi4gCu@f6w63zmTN7eX?!xinzdZB&e%nLt1oOcYWZ*-0RqTgKfuxe&3|MPIL zY#YP0zs_axJ75Bb6Gc^;D*HShmCTPy%YSkmcwu84NU0+Q_sL#y;`!Lo6cxy_PFQC& z9NeI*sPd{gwbE*eB?0*jx2j9LFaSN##A1HIesz17=LsBc2?$$+pG7>g3n}Ky2r=*W*GxP z5wqOyRCIF@k)nBjZ%)Ie@#QCp8c|ceqvp%Hx*h7Xn=Wvz=aJ*}AsA2kbI_=spkK(G z1zcW!O5vtLm7?gZu3}Vd)bm=l70iw#N@b0 zLLB4Y>hg$g+6miVd-AmKn&QIzwHe1`So$yhl#>9+EOfgJ5bw!RnG6x1^eD7OdZ;)v z?r5yy5lMpe(jj-DM_n3+d!I`O>uIx1<1ZIkCV*rs+F#;?>CY*>BDiC$hW6ZZpL13u zKYH66%Xb~@8{}Km=v!F6Q`fr3>a-9KcK1Nsq(2`$+lcByc$7@4Z?tAc8Re&6VO_G6 zt+i;q|L=?jm8v^4q~Tho8fnT-gx3*ejr{{?2{n zld|cPkB4)C?VXz!sZ+kd`^#vj;uqM=-s~P=xXC7vOWDM zWtxA)Q#_C4wEkS|7+-jHu*`0b{knBZQmsmEhP^%s%340nrxi~njUYB3oAE-OxFQBz zJ11Ed1Bq&9km0%Nx+xk_`T1rq&lWsC>&{uvt-qU~^fdCJ>X_AF+(cUF!jo3ztfBt> zDhTU4TBKT8p(nXjK5VPvRxoICT)k%?#5a$;zd&$(GZwM^+xdY3*1GE{mGSuOgRv4J zm!oAmcNHxtg}!QtR(k6*c}eZW-sak)afXi{#Xn21#I)hvCepnlzjTVwbb3`HrIhz5 zR>r)^Uu?9txqBtiAe8eE_p?4rv9Sa4Ex53xw5>{Aq6-(>!q(yRFKpr%_~rx3hfM>| z_PvZX+3YR6``i_in0n6POr%eZ1GVn4 z|1x^9qojw9tuE{32bGpKlDXazGSO65kf-x!*}ADg+B$>bOsgUXn_8!w9p4 z?HR{PTJ}xcQF7AE;yYL$?l~CP>OMMZmzn*#?!A}!%86~SYwlcLpd4R$^_+KjG;Yv; zKki6t2@?DUrlOslZ!L=MQQ$7i;`A5}7qCBt$C8CSn$>H4r$J@viIt=U8HbHt^Lbi^ z3d+axPtI$UwC*U1S{m3<_J*5RqMbQ5tX#6eE9DgJcxw7J>4SE%^P4U^4BBKlhpz-A z8s-n#;u-40VLXh|oFqD2QYz1cOrj|FS`3=WGi+VS>4mJuSLYV-uiBiDoHz^0#-xY# zbb?!|p~O7JBMXRJYMpq)YI8rM-Bgm&cl2cEq`JrTr8vVC1jy0-(%9+%pX#YB2{^D`@ zCCPoK&=?=j5dST7f-$`SOJO=xoOY5B(RWoc7&4l;r23Bc(1@Y`54cB_qrHfd*E%q) zzd$XMN~X4yD8eCg>gf_lPGPj!p|g`qNE17&&R(11+zA0RSGcEZ=%`zGspu(7+^y0ulb!dg7t|G%r(qU^2Zow+ zV5&JDgY1~MyzDEce8X4eZpn5VI+tbJO?Bq+6BBnt^!XoFSLQXl2JbbwaFBE0Q9&l9 z#15514o7!?Y_4Wz;aQ5$;Rd8MfLfYsCQp}x%E>nL^tq4aZbCtO|go3 z_%|m{u}2nsXJhmz@38iWMt3|v{({wLQ|2>^n8~iETO=|k5)xWV6x%J!^@LmRJiV8B z?z^DMlZ>2_!;ZNYR8$y+mJ&FT`_tLF)y{=kqc@XmOS0vgBPIS^B+IC>5cG|`ojobR zlSy&ifpSl#9zMRk>GUnUc(fheqOW1w_<^y{ZDIME(GIoI4Kbbx^uTWQIxe^D`f&x%APmL3?(!jMBUa3fuZs`?5f z!!vIg<|$U+E%J68m|SOSUSIFDQwZFK)z;nS&|2@Y^!|RY@SInP+|j;g6VtLKQ5Oa4 zf&|{4@%I^|O&U*?IvrN7BMQ<5%k2*cz(vg9O{GT@-|>~_Vuo*rb_{g9ZxD&5=J(fi z#hHc&m!FLIZR4u2w<6D|>(`W%i5(3ef>Tphby}{=B<}uht^R^)wT1Et@c;sObdVX0 z!)-YkGWPjJNdRas<|4?-=o=fM~EGC=*ZkGil=WQ z_rp4g>bv*gvYgc8xGYbj)zKy*Aj zrHlLXBs?2?t?memgwC4tWN2&w)5Wp6b{4k^{mdj8n|3&DMENzfvg&H2!}@L#_XA}2 zA}PK!ZFws{MfniEr3H;_ZC`ueXz2LrQ&KE5-0HO>i30*=g53q{Wp9%@1M=QW+{fOB29S9rI} z)Mz%6;mz%5fzf4b3qHi!eKTU+@3Jd>4)kb-(ui@HNzBi(^rfNO!G&-fIC%Mkc%CVm z&gv}cv7d11PzzrmiC{WH&_6fRuMY3N&HWvW5I*gXAd`Bc(;#f!ZA;`iLCogB8A9@j zOz9_AiK=rU3=I)D43E|IveuK>9ybq7C;Q_`j7=CSDFLO8sfr~37+uhdK<0|PfS*;a z4y`$H^=A(O^13Logl8j8#zud=*DNN6KDIUC$L^lec^?zEks3sYJ-?x4PF7&qOzP(s zJNeoJ18PN4o;}6&B|_AR1Lx^UCqEa28TIEEhMkvuwPazt&BtS1Ng+z4h$jm8s6SS( zR5KK2a&ont&V>2*x5pW$ym8X@AisV4D#@*AR~-dL=NW}V_iOF1rLhTD(%-fB>dig;QyV0Xx{SiDQZCA8&M-3IFjLvx*4 zpx%i5@cec7S~wse>o+gCUq^*)05F}yL4S>XYcwG7;-@0P{1mqjPY6qt-d0}m*`m84 zcsf?z<)Y`|0~}j6>3CGSYHL;HU&4?6W{3Ira(}E!Fspg+el%?-VlO)NO{F%N4mDe$ zE;cUzzdgY~&&2(Q*yC%Ok5W^ddWwURE^r`AeP2-H6=Y2ePs9H}}j$COsh6h0pLb7hveu&>`cctv4H* z>)`Bp6nu8rOv!LYM-sn{xtkugG0C@)n2s(I%V_X;;2_VBr-pCv|FiC9$r>Qhc5xDIH)BRCH3yT1QdhYoecayow5MRiU!t}}l%H$cD{vJ&? zBSSVo}+Gj|7#sia2N9Ir9*sX`Cnkx^q>B>1WSfIk)4nhNf(51UNtwa zCd0+gTt%@Ii@W?ASsZ|`YI+%5?13b(2Xe)iJ&s2HZTT)=s4jFfb_!c=;3owk6QRN` z4>iXHY?{!cs^S5bxXc&i?2;e*6@V;;<&d<62_9izG+*i_yNpUB;4&@8&c)0F4o7Gp zrW8W6b8#b9Si}K)n00={>KwTInS%#(Jai_XOy4lalas-e0rUe|r;ow`yaUR-5BCHZ zLnJ%LGMT;=N`RZgf0Zzb@Bg!&hFP3s`f2I5{5b-9B_P=8Y+=&wsjl?_4`Z?(m@f$o zr*5d>l|PtGkHJde=w-;Ga#YHvm%yW)-3e$tSI0S4WZ!U~A;hM0!fBlkw#O<0yA_~& zSihFqx44%jF0r;I?O`sVMkKYd7eO9o{V5cglhH}lkzw~9jQwzq*W%gy$}pHPy)c;U z^|c5SfDaj9frW<3KZ>3d?Bh68R16-?bAcTelXPi?*EnI?WXc2g@rN(Co44P5?Y$i> z*72%TZraDP?OCZ7N&Vr%eX4R@?JYxBoW0@3q=|@ca_frs|453hKF;HyCq`|>UpC4i#n?z9AN({i^$uR`QIg||Ea3GvZks_eH-U? z#%Y-FUQ%I{30z=j+TvsrM-a<8_*IvF47l{0;g^@#kPv*;{y@Tf$j)gX0y?#)tYakv zm98b3qRduDiDmt&7gBv-qp|vlj8!peo(UmP2fMNUk?1-OlM4;RG{1 zN9lp+rgu9(UAod^^57>j@A?&r zyb17D&Xh?M>D+x&YP-jdLGiG#^`3zPjuktJ^i;=T)-yQ5D}MM+KTJH-ntnCAn8sg` zH~Z>@%*+7i6RP26TRWj|g9JF**j`0W!N|KwD^923fQn@VoqkPJo080$z_2=6QNu&z zohD2+xp6~_|FP_mr00vsy}lA1s0a-vmzn7Dsn-jOJ9&A|o|#EZS}$P7LGPrkcc)2` z!v%oH;*+?7{mR2%rBjdE&FKXLe%58aN=$#O^VHVry_e)$4@3qWvZlOyeeX@uYmm#2 zD@ix#SHp0K&07yRLO^I}*ur$MEqxnenI63qHn)E>TsFSeqq-1faBMmLg zj-@USKzhWjl3p&*0g@-nV)o-gMz+dFw?Pa)`mCQDbyGIg({v%R4-8HAG4_sBE@EH@ zo{2+)898q5`>eLa5BksGs3*;*FaL*);2&0k|MTDA*vE}(bu3*;oa7Jk_#5Q1hST8H zmFjVf4bJZn9hHihHic8>Ye0!nvP?@Eo=?HmNNX3c9bTk5mi8#oU6aSfi(k~(btx@{ zKjnM*c+g$?%h?xp=mgahaVxy2UjuNo`AU?b#^J!O`oQp|s+3xb-qk3!G0iUy`(0l* z^zcsSfncuiz_yfUh}d^8o6d5cFtH<+;rT~5v^kg)Fm4_GSx1F@o#o-)r8r!;3?idGQrA(=PU;`O@ll_a)O47NZc zH_lLQc@)*_GLE^)zOP4JgmAqLr68zy4O2o#yz?iuUHhfB`}E|q?qSs0yY1zvSAzzW zY<%$oKbaquJP#Z%aoE!)BerCed6@yh&fcu@i*ui!vNaj6)Zf25-lliBp?IIugc((? z|0e{ZZt>3tgusR|N&b-QgiX>7?m#l=bVvxH_4|?2ge$Os_x{P0!~Wqk-E1|pEXEA5 z{WbtVo5z)w&=CbmaVsE(Tp;9Dv>gBzC(#WTAeZ-C`BS?fyLLHfPBMIu%F`z5FyNy!!4|TRWqBQ*s)%7J zK4$RH-SNNImyh0ISAB%}c>?DehZ0|rU_Kv&!(L>!bA2yem|Y5V4yWsm(!jFlbX(d}#BNLl25eRi^vmxB1!4uGsC zuz!eJd+&(fMGw70>>{C&t3BrggaoRpHO%V?gboPC^VR7*!tT0Do#blISyHfe06qPu z=c16^_TS`7*N{+u#H>l&%60}XySH3~b}7b+jEb52_jP zS^wvO90Q(Nm1i7=1KG@BJN__-H4~P<&te{+W>i(cfqfAq_Lr4MzzPZ!4%tB8;5u%q zv1YAfd#fLK!&VQ0YG@}b8P&bY)F4XuhYEV;2>v#4ifz3k12jOptU`m4Y+!GIV81T_ zwfugQ!|#04(dg?wb3T~+Q`C1Z#foaq2a|DW)Rjtedij@*n}x17Vw=0uros-&o=y7* zcA{7Gmj!f7UXRzhc-QDYaTrr0lUWVT! zwT>1!(xR$MS*m%|{-!BX=I}<(-C^%F^EiexENP;ZlQzc^X@=$9*S(Y_oVsuCsybk` z-&}RNxyY>|o1Qm7A>5xX@=LM)iTSoyKJgr9%zC2tm)%^^_GuKRQ|U71LDBKgPan<8 zPY-9uD!3coc0Q_#d(U}t-EjneD@&OF1@DWfF%J|%$6J)ZQ18gG_WgO|#YNhk6 zRb5X^(R)EbboiE^!HO>Ar#hw-o@$#>x_<>xx?_IO)gUI+xCJ|rd7GR=ZwQ+^_%}z2 z9CB6aZ@@Xe!MAtdwHN>90F?rw$Y4O~jL~Q6{DaRX*QB-3&)%Pn{o0r4RI82&N>ptu zGDyLU#qDkE)W4On`&CQ~PYJ)f8G*bt&0Gng-jnB;xg~c1xg9@vEg!_3D`UK49i_-& zK$H<7(mOwadf|I$x-Wa^whhzSN3B8rWs^PUA|Kr9FM(uTV_p9D-&MM3UhVdL#(pI2 z7~CW<+wjITPWvHhfm`1p{P=IosC_UOeNEi9r)E(Eh+D2B=coSW_+A3~hL|79(&HyS z2gr8K{PjJlHPYUW=SzcB_pxllb7iAaQ_UaJ!z(BRJv$FM zKZ{}oJGCf<(hd5%^~-v1o;03iPElKyxo}#48w;yjf%W6kGf6O+p zZ3FiYF7*PSP!aj#2m(eXcJ$&JN9P;$oJ;o-9afGc;C2=-76h_)=*$UH2KkyQ@xCT; zes&X^q6zl|tJYcu0W@m%oqd=N-rmw4-j+Ez>Ri6*)%3R(1-ue_Pr2qSw?Aky{x;=K zG)kGYxT?1pbQ851a1=#JrV5|qM-IbDyuWtK>$c6glDlPld|!5|^-36cX~?4Y8jxn~2I`XQsz|8AU>fvD3_8l0Ns=BNZ?|1n-^;? z#7DfL<~?{9KILM=c{X}cX&CXL+Yxz%$YN^J&oq}OZ9HUe_!9ITEOsQ%Q7aU68;bgt zNWgDJm|E|g%SBT&*JIm5l3xH0$Ww-Jt>oUsSWV1gKe;S|-&Gn4{E*%p ze6N!R8rB}xRkMW4@K<|?OSi#HK!$cp9h|$9U4UGuB$wSCO!*}>yw>dhv=h~j!yNn-&Qm}dDoLbawWp%&~d?Na&WDoCun;JzY#58~&?DG25U=<=WLVlZ&^S4FPA zI{bDMk5w1`i>cg`zd5>HRtB3~SG4^I`T!;8LF*C-@~Uqy9{dnhNbDj1XN+gb%H+?z zi{FxJT&D7wGgw>udZI%UzTb~=6na#Fr*B5m&GBW+^dOjFxazapOgcQ%xsm}Pym6)> zjW8j59)@J6{G3D6F(}ZDs1sM;ArLS?Q&{y+V~eKOD!BH~tDXo)bk+!wT2jIuj7um6 zH+ae8`~7i8k+Y)g1#yOQrYvi`UL&F z8wq{&Zh-E0vAaKnT9jZdsb@;pOA!p=n-x%c1bl!|*u{>zBm3{fH(DbYToC(Qj{{_q z2s;QDhf%0Ldl4#Ezs7#;WEOpTU};|I+M6F2J9od2cxbgO!qr@o&1W3oLn+zZyi3mZ z!}_iKt@@FypQK`L-7P2oI&1wwJPj7wj!x1t1y14&@eE&hS|KhE!c*qqqyS$e;HVm7 zfD*_*v2dg%ti2PB>mL$<-zXpv_!ff)4uM!*?ArvN7E|2PynfILBpt6EeinKO6s158 z_30h67XKd@VYUV%zTRVhNElRV*Aqq3-(XgAPb}}PW_J4|4ctOaBfVS3mhIjaBz0rs zp7=Xwv|iOZt!nq(uTt|^llnB`THf-x$eTMp=9_0#f6C+3(n&<`dGD2P=fdx0c&6sPmQo)ELV8Mxt74I&)F zr=xke%geX?fK7c(&Nt^Pk|zz{x-}P&!-(51)27P{uY79mH2Iv}rjz>8QI2(f8)CdyVZ3Gm>5vjwm}_XkJzcUqj_NlI z4ZsvVeN}@yMvru)_B5AK7OI?bN}dleTR6^K=8V%z!VvT6y&Zup z*qCsqXzzj`K2m}uxw$B~;cfD9!ME|KBd?yIT_jT<-@sgHlcgtJS#M}}J9_`BGuToDOegRS@8Hb?9!GVGkr)YHV zz1C5?unVpEZHG&hTBYyQDWwXX8*T%eA$p~H=6&_W(dM@amZ!gG#n6Oh#YvYhnBR+2 z!jyf_pk(aV4nE`leEnsCxS4H*S<~NUDr>SLvx?>6e0*CHqwO4vUX~)Wvz5PDO9Oux zzcNGaw|`w@vtk%9`$^>k?$;1`5j|vN7INCaPyWW(Qf5gCdS7Vl&baaj^ot&9BCp?+S6`laX+rk8U7&r z!CzRDxn6Vz)o)GaLo>|b-s6q>UdUy?fZTM-{Yji2TI|^+tmTs(bA|+ZV3~6NyNs#C z(JLD+?B_Y@7Pq{FbL&4BfnjZv(&PhdQ2l+`&*?WI3^}ttx51k*LsH=Yy5qX4GZETF zS-LkQ5|t2Qtv*B?Hm)i@<46luv~4jf>4sy#k$$wTq$ju^BD42b-<^m3WOfWSv&}NQ zUGYGw^m+B2Z(cT?to?uOf&WrnL^EyKstfgX-AEv4EWxZ=gL?Vvr-P*>Q1gG_63kb1 z1(EIRlgHYgh1#s6NnGZE9rUuW6N;5e=33deiJ##2fcg>D&?VOp>cZUtxxwfDZkJ_@EM3{w;zBA`g2$;XvSt z6B%_F#r=m2kW_&axrPSF81Il$mr(2W3Zr@aZ4uexXr`uc1O!E3}JYr!NK1ST}c$bp2$tLzP_w3l3m-bT2(fpdOCg6 zS6)M%EpwCa6wOa{*N+-Od51SMo0cpIUYJUZ2+p#9#o6f;hNlt>gr~RidCS)aCJ1)< z{2;Gm*gv(PN%n}*9DlakIJM{Ji(l6Yiac{Tf1B5#L#$%~-3l^4Zt+kF-y`1pyk}XI z;;d;s$$iMp9b?uO85uP-?mJ!G3OR)3BHp-F-oWY6G}<3Bc;1dbrRux5dSu!kQu}c6 zJ1q)*^hkkJrhB0v`+|=PJD377SW80jK!9hN;MGpiOL;k_+C%rLZ?U5?bN1d*aK5t5 z#6|9~TX5ekHTvA!eA(kuU*{qsiG7%rL33|a>8zaq8p4K(1Sq}{m~!otCA*872ii2` zBPu*%qb@xA+V#o2B04|g&XY}5^|j%hUwlfDOsaxj4Il-bT@Ve&ZDO$g*VcFwm!*Xe z7Bfumn==4RHXzC}Z#o$-;1|`-@_PkX?h+vjNQoQLQHv92bIxr3?=L=D!xuTLUzo2` zS$$&v%xvK>W@(;XXlxkA!-?45*+~R*MTmGg7qH|t{PfS%RQYu(|0xw%Gk<0vY^+ez zP&;p27)Pf2xJ+9;B%fEITSR_&^ZH)c^$hSto+6Kf)=Dv(ZTUdD!7)!hdaM z`YL7R17GPuo+;R-t`KN8T-LiJv<5w9KpL3+LwE$A0tzCffW_k>;L+9Kvo(tc=q}Df z;yRkoEO{M0Z?P1g{X6I#c3Eh-mEflC!ngNmgh@fyErb|{`?P&|2KHdbLWp-VCgfnd z>-IN4Z+Q^)&Ac4T<2-|OP%cR$BcoWC7XgM{T?tX>*7gQ>-MPtR!V{b~W%5jwo<{Q> zXUwtqYD(!EnnwZqM zIBK6nA#h#u-~aSvv|YgYQ}LQF*1d^8dh?Kr*_ZTQL7Y4l|8PF#hen;o??U&pSdspg z9qxUSXAeuHrZ^weyF*(x!fn~NZ@v({)!sBC`d~6P;^U?DoToSj5u^5wKOyX5Gp*)J z98W-rNQZuZ=efK`re>FKHD?cnU-s0yYuR8=);HAu7+r+^j1z_2GSYz%o-u-&vwBwq zXmtlzb25{b#N$ixGdo9+3;ci_nw(D4%UMTiAn}FaOlCTY_B3_YtAcsIc#C9v8153= zYSGIo4w)r6X{@1*y#EK<7-pl5RSyIXw!VE?%Cj~@esW{2wWpLsDE_c)Ij)`t%yDqLIVya)jo|i8!eB$#vHzz#0UJ?t`8iQ~!^krh3=ry= zI&jcRW?0Z%DqWV8q-CJWHrBBxd58C7gdVw>fHQq=3eywK+-OM#)2Y{%D7EzSfOXvA z3X|3wg3s{v#+1u^Z$Od}&jjsvg14N63$qKaxG-SvM?r94#y)pf4vLD5O5VSqsx>;7 zL7N*gj|&%`*ZLUOI`ZSm`@>2C3~}ngrvnWFy;e?p%!Cdm-rgRMvZ@BLC zJXFsirqORK_-0b}s;?kPJmdSe&su?f5|>Z|3;2~GESXB0EbM83LzP6g;HLLe=U%$d zjZXV+mu+ALo`8F211OOBxZqxt3~H9^tbCiLN9cEFSeEoSB)p0rp22^$&_(y#KTX3n z|LU=~^EMAZSO?Ny@jkmba{wmctlHk0onv6E6Lw(= zOZjTt$_OPfj>`&}9c8EI`FH!|{1-7Im`z}}LZDRYKbS@4h)O7ulf1ly>P6Lp;|iZ4 z!vZzGd!M$;~g9uBq}7pYa{@*WoMWth;<>h0*odOD>6m+rTe=o|?b zbv+|g&-PI}|ALnhPUYgkk6M;6H*$U54%SX~ed;ERo=xz)s>7Nvx6JA%e*DF34~^GB zWaAZ-!sys{UZ0Td;bBLahCu=d}GIwWj|vhTr+l_N3NM zbEk#y>}R;*SNeRM(af=oK9&1hy+o@-JLXHWG&=1ncRSyta&x%_*B_lEoSGMDZ0|6P zLl;nx;>2pT>(&PCgo*UMCmtDO2Y)yHzW;0%N=x~zF zqarLThR+rk77=P^Uf+q>WxCYBn9 zH(>D~jUn9_Yx2P1%A=FPkJq7my3<@Ji1HQm10Si(=kM$r9EFR&eyZi&bV(>v3mCH6 z*ONcOMLTQONu1ON#Zaz&x;F5=!SbnD%gGzjy&X3$SOlI*+A%+E%h6IKL7grw*`>Gr zQ+CW$pSORtM#tByx8AI`fAh%ok&`y+S4ipj;=HmQ>*I0Mf^jF6^o7hvM^)T%vUaYV z%Rks3uy;mDzAO1ezu_gUo$b@jH{kp%8e(l95!ZzXb&1NjAXdZ%lB>XqNZ`c-Qy)#A z9c~qvovc5u`c1FAlly|oJ@=gh_b5%*kAK*u>izzwIq&2*v)0K0xm@?{dNGy-Po`b5 z3b*{^OXpsG)jt8Lv5q5>RX6=frUgl{*1lT*`YBIyIMNt+^8S2~B(zEiAim*XEPNF$ zbXVVkg!&Hxinf^k_hA(d6|DUDoyhj}2wlZP4!=nnw8gam{n+9zJavms3ft^c2xcEQ zz(nBZd7;L;NF&VghP?R}(%>(2f#BLFom8&F1Y+vEk z%rZMM2B2FjB%Q_GYcQ~+ntnX@Slo}I&91TudY39D?^f>sdbhy-#jqkWf8Jl+B3D${YP|kVjG3U@q}Z6x$~nVumXg=g zvXUKylYylhR_e_!#`a9U>Ae>nv=JdZV6RL&{)$2f^%rWJ*VV`wwe5VLCK#%!viHCS z?YZB@jucd=Tp>+zc>|G#KvQ4k-Ltm3scfYae^+akP}BRmZ~k3OY;aRh`mbT4AWNp3 zzS8f0pazn)1GQNBV(aAmC7q*6#q(LRvJSkG z;dk8{^jNvW#bjQW%Xgadm9iFH0*~u#dP!Ig?gX=D?t2!%%*UVxX*Xj;SW!b550PcWCnb`#dcsyo&DL+XVTao;gwRQvLxosY_^$iftCPi{3b^n!~eqdwIA@xlonWq_s z!-n<=?cFk8SVBAme(Vl>djh`Ssz-y04|c}!WOjAZeN7&Dd<~ zao&Y2nxD{}>gF)VBWC9&=SDL#damV7>IV|vUQhAi{&XoEpU|GlYFIu;Ovn8d+i8)N zUwj`sbLbIe|JZhIx4_wBNO*JkD~JR^+-{Yi8>AI^<>!G0sEi-D!U)z9n~NkZ z3mFQBs6v?eS-Clq{wlh=`Zvea_z$VnQTzC0{8#A~R)NY4Nwq=An}sX~>SdU}H!scVH#%L$I`SXJ3vlSvKKwx51}r<&La)fFUn4aHBm%4&&GG zn~;8^kUXcIyJ7z#Temp$;m zb4NaZtq=9ly?|$~Z-2qift?Rm!0}(?XQWe68nFjY2p!m8t{}GF$FgByjx?iNTiijY zWxyry)0l7bAl}RW&Y~DqGw9h+(cxs`iaR7_z?TX1-|UfW2HiVQ9u#%L4ZhvsC*4VA zrF@oTK{)P5d3^my6f;)8qu=QP-wIEZ+{$kNnpUzLH$4g+J9=;s> zOCZ>%@18+uqVlPI2UYA`9Z*a+mmzzpj^eU$mdsfAHz)g?IuMz7-p?+ zUpgddSOGUe4jZT(kkEOC#TZdAgmGr!Z;tuiWy=`wKCi_SX7pM>$?1+!8}0q|l=YV` zhE>^B;tCD57D7e~mYYdoA0nANe`xZ2m`l7VdZ#M4wEH|F<(Rg2`d7D~Z;Rpf6G; z-OB8d&6zs7{%z(p9yKzGN;mC_wRnoXyy?9(p8N-wkw$>~DNeoq>Ry6YwBeAs72SLQg^%mv3V>S&w9PeBVZ*1r*3VJYBLAIR5`k;1Lxr^m zEK-=Q)#$C7EH1bQSF}|#)Cgc>E=WPF_&{tCa84)S?l9}XAg~T-ZGIfQ+WzY2SD3W{ zaMcYK0Xxq%GCM_)H`~1Q>K=hv_-`rX!na_{U{?+Roo{G>G==S@i~h~gmVBX@Yd6D< z?P#or-^?z6ryBLZfpv8Q!}&F8McD~oeuzH466eC=2B@lzFW2%KXL*mVzWlT0gMEmD zJkEn2jQR}%Fe(cYDUqqgB|8&8PvIxqpi8;X<|0qffXq!ZHp9w>Xdf;5G|L-m7eST9 zg!stA;0H~zO-_MuVMv0J#7YbhE7ZVHN70LIf^;-+iQ^j{ATJHU;^?yijRmUzg$}4} zb>JGs*o^E)Ke25+c@=!rHj#fjJn`EBx4F1N+0Tlvn=k|>*iMI#EoGLHn>PZ+1oPr>(=uN}EKg<|c=H=Gz6 zfTLtD^n@3B0;DntI-blrSZ(XbE8^?s4y%0n0@c>hIPkSKu$lZidiAwj6^2^K>N|rTYT>)cBguv zpj%K7dqOt;DX9NXL4vTxl1`T(Kdyu$>9)OFQ6rb(9Wsm$O&u9d-U@kv^O5)2j~c~L z{{VYsLYeH>Ub5=_VVn|u@GNfp{JYJK6D0#&EKwv(@W|By(5S(WLct=6AV8pPK4!5D zALK&#)lhvIsMA{D{8RdyBLfCD_%>~rG1Ed`eLi9za%EA>TC@@++3OW;noF$657wHZ zM11Kuko-lrSZPAAwY^qc^b0~_l(nnHW#6l;8RscVtm)GuFW&bh@cHmA;~t&5{#o+b zBb&^l{FX(47yKHSw_S$LDYAq2|ESE~O}Rp(7=Z#n5Qb!xswuWu9syDCj3aQwujwGzpg4)0Q}zB_XySlPi&wA9f%Z&+&iu%|IcyacNvy=Ke4W!U`EeSl4r+5A;9 zqIia5JZ`j6_4TsQ`__;`w`z!0J2%_^m$+s~uIZM;qk^X%s#V^}*_MRet~6<7LR&zI z^mL5C6?;SHx!~TOk9g*mqNLKv{HnMU4UA&>jFG~#4`+|s zAWnICYyKh{2G@C!t58eg%4?u;htUmjT0=O0VMSg^+rUzLE`haK&rudX3Ahn=?RD7F zz+`>H5xVIBLU4pS=CkKnzDTs=2nnzWm9+@Rx7@;Q$y zFIC%MPa$8B`HTMQiGu@knUka!zwqEgK)upZ(N2&I2f z@LL;@UC|~n?Rr56P%mT)o+_Ez((n2;%_YB);%Sb3H+L#TA4%I?gqlP$Hx%^SiG+X> zPpNm2zzVeOd+)nzXQ3`or-S5prTI_xw6~;K{MG3tMM3<}11`)h+RKTNr4Q(}%<)z1%+E8ehy- zeMvRjsw)u=Pf*{tXcK&f)4Cu(*iRa11i>6XZ#X!>a4J`{&Kf%tognm#cM%g5BFz=T zDgh#aB6-UK+`dE9-7?J-%>eJ!cl)W|EmU^~zuSv-bbJdBI4^szRBM!6m$c&=d9nzA)a-@B+hYvaF~MpZfgaFYmoNXn8SM2 zO)R;RYg>3TB?!5Hxlx9n;nIKYO_UZ+|7}`TrIhLSAuGwP$FV$*isZXU4{|8F24(G) zC5ppU;`R99Wk}QBMh^P_ID5~irnP{PZOyYgIsMR2?tCQui}2O}CqTNHf@O=eKczg#g<4-5HW>lPh4^>0mnmo?bb2Q&W?gv{ zLxNobE}?RB{5Wl0?dz;I$d2L(a1e-Qg?L+3+kpEgXJU(nb)SPRkL|3*cHHSpaXl z<*yXU_qX2nsdvTs@R34k9i9j}Jf_|sC$~R-ZXkkEFNvt&2w*a1%=O-9k%@|j7@(ey zA3GRMgr*!>erQ2<*-o4)VX*n+Cu?)Bd(U2Pg}?su7i;`A{u=a)%C%i4R@f);VVDEJ zjgc*u+aF9oPaV1|`UJ$6_8tkYPfO5bWU%z$|`0NV>m@+(-5Jx$%6}P_w z5F!_d*up+T{{11iLhY_+Ld>CMF0Vxck~0S2pkAq4G^B$hdLvu(NSf3T%MJ?dEHVn6 zG@q@qe`s_M1oFE#!#0_RVQZssns@g=FdNv<+Li&J2WZ-@Pay`EUoS-KKltDNqkUDMr2F4r70LP%{M8ql|L1aX z6b8A!IG0Ns#G@(VSoRLPLUtBu*T0<=b%r)XU@+%G0qWxcV+5*As&%I1D*;sWXOL+1 z!G1S2vKMIkJ4k7Si2rm84FIMQ!eP_2-~MgCLsHb)K+Z9g$>)6?Kb^%zk&}8uEjl=^ z9iuH_1`=fndmO=*?NRyz#N~t00@CohAbezw=e;u-L*c0|1^V0?wv&cR*B6W@I zo9DbYURg8(47^_HMIF+JsIj|6HM~(Kwc!{#(D2v@WN?>ktZ{rl;*>Q$)itb@B${?% zM*d)_|71;>ByJu$e8!5&_t^*U^W9FIoa~5vrAm@2 z82|1p)K^xY{J`Uc{TJgyUXARe#3?j4`EK7SyqT-6_Nvw6H%FV#-@Uc+P+rLgmK#K$ z;peDH%Mt1jX2+kKCGEj2^s%E*=*9UV@t#9YVeMMc!F z*+B_`t550XKwIVqc*?lw) zZne5nIbXbY+1VTV@@a6DcgoBrGlf2cWX8K%&p^n(MT)rV>ytA&(v*~NWTNNZ(esYc zOogUti8((93k|c^G(-ag!_l53BZ6ZKNM)wrs?gB2>Gk%_Iq`#$MPcmcGJ#@n`1c^;?!TZj*Jo_j%O0wwHvWQACguxnd_oL-NIL!=wo_q1$rESam~?m%^kCR{Dg7+3hg);Y%5IpxS97BBaqnPg zm99bP-d5Ue>Cd^^ybl*|KQ}Hd&NllS=Irda< z&N!aLqr-V&t;|KDTW_O2HMU2WmDGvNc^sTOvu6=Qwk2uez>eQff!{nBY zV|6-Z%C$uJO*UJ9BC6T4I+}d)#G6dDgwc{k9n~+ahnSkuPz8DJ8pW?)TlMZTGT;ZoIwUPRy|rX>oy3UWekl73Sy-p@GPs8d>mY}&APJJ9>fI-nR2%cl z3Q81Z?QfGdS_4X!d41Xzxl5;SL3YHh*;N2_qAR2v7WVYzUS0v5;pMzEh-tvS1xw2T zvd{g}Th=}KR=bZzI|Qc|PH=A(_;o2fBJv^qQ`&C=`NeahX zZa?6Rei`g#mNB?i;is4ROyhI))@VX zhb=^Iy53FXbt$&Zzrw}8m0B8|oh5_8i8QRn2WygD8fI&}f*$sMD`0&YY;=1f>`MKP zJT$*(IivE!a-X)kwnjKuMb3Vg+FPaR1cMlM0cbtuXj=x^B+%Z-KvePI8v=K2YR)67 z{E1D`kvC1grEhY!1yn=*`LDM00kT*I@Thf2XUDH1b?jf-92@DPxg8J>%`o;iwBxDDU}*;j7h;4NzIzSDcm*YTJ4&jm%=n=XW|t0Q@$xkox1;$04{V>Mjg_D=STGcV;xs@kHCNP@h7Bx##>} zxuKTq*U%1>x01Q#MB9%$@s*zfIn6G|)WxNoIP5Bni-r-kZq8^}uIvg@65pdZS(3AV z&^<;e#aG7;VYlut2NeaRTbIT9P~XRIIn@9S3MvJ;HkrGxhar<&fD!j0#G&mMb$Vw& zta>WEqUSfAGFUeoyF6Tcf-E}s7tjv|lIlW&KcY#48R3TCQ~|Nh7Ye64YOAq3{dliT zZl^IVM7B;HUVG*`Y%Ts~bETA{>q+3KA)2;Lvx)nAY!GX(Wek!Z0hl}eo6a1ZW`ICP z*C|av-__E*BU1O>ahQKiB><01GnD`zbOlutCV;d2X_{j_WRET<;9B~#Mk#_o1inbu z70KEnTQ>5=K3ZM$CcAXE0`>yZ5l$}<+=GB7yXlh#@LjG=sRD0(Gg1yFb4l{0BLY94 z_Ee-}^)cZu=-vH+~>-@9O{OH^3M{(T|ZDv<4_O z$)XM*BQa}tFqxy4jW54Gfz+Jus7VU%vds(47tjD%~=IdI)H1z{C%aAx`XUf~Fk)XK;A%n6(8k_COPY%{KfqzM$6ug?y z4ZFa!qTCkn(8sy(js4D`Cqc1TT4SSWtpSCAoe^5s(3Dolav4~G8J^lFiCfM1{kV*( zOg|#exnOVcEeTa26}#%g>}MHx=(dolqMPQ8>#MGdFWX+99E=_qY_7O}+Kc{u^~Aqs zV<4O4e_j-6t;T9EBM8W0i&W67R1MG|;QcQp{}R}$UI%;hmq=PtB*>qnNSJY`=EX4( z2r@YECzqtLCYHSSKS~3@Cf^L6h5fUG0CpAsZXx_H$w$I=xWL8&9ac}$hwtqnrzJvRq}1@qRzgU>Ng5kfH1$|DGqRONBlwtu7zr(1Up@1#}Gdn3NU=!k=5 z_*hIBVrx@*>vZ1tT670RT!$Dqua`NYwcsg99$UO8EL~!>g$dg9w5eXq&031@ zBFbpS_SxN&g-l&z7~ep|RqVYfUDb=0T{HTG55WRQ)M!rTsvYzK22r&a&HsOG-w>Dm_MT*7yz}^zF)=_Cg zs+^KKerw(`KipkO`^vjQ8%x>dz6alP+CExHoQ#f-Udywrw2EQ?>&toRhJ8m8Tq-C6$i}k*XX!(?xAuy9$L`93^$)<8#PjC z>P?{;JB1vzo@mtvX7#TCT?B6Q>vH{A8RF@-~JVdD>q-iMEU*| zpf%L10gJLVX794XUTQAiwYX?eQD?DOjk6pnxmhXC+PHJGUOsEe%>w>aLVw}w0pmVk z5&M@@Wsp6l(xbCs5Dj7px8M;Y!HHL*_$v~|Iv383p1oUfjQCW%r%{2_0Vk}re!ABy z_qOgJFXBEv{H8d2*H_y&ZT^twN;YUx=3RlaL&6wV_In#1>vN@-#7-+Z;ntj$V}8@| zlWz?}&n!GnvTQ3U7Izg*v>d%Os?~AkmGwoZoQyRiBl8=xuX%MuczQqMk*uHHIan9< z<6A@6Zb&g5rdwD5@jMpI3M_H;XZ?%)I&MapVXTHj98=Ps9eH++a|2s&!=kTg3uguvAv8x`$3cGKNoONTMj>7g8{3x%>v2DQf z5ln(#BDIjq(8sZwvFd(5ibTJhnGChyx;3b&yA-#-H-Wb;A+k*Jl2|?`TM~#|zYq~> ztf!UVMqPq8)ZOMI{i53qlYCD7tJo}MF4dvA zKBdX7_1*a2U>7%fM>qO`?<=V^tmGSbw#w`2*-?yavO*6C`3nmP62hjiq}=V)v~zu zN{rAnTTX0rw(F}{eMR%aQr`{+s;F+<&H$jpIZL<;O(TOk#jo|=Q5%`H5CS=(IJWp=y2-eb8Z$9u~sFImZ892+2fA=YckXLFWbKc$Q`#2tEz;-S4~_A*>|0ou4RkgdjI6RlE|orBy(1G#aUDOo zecKa&6iyM?@=r%Vi+}@-1ZyiVzOHA=86WJa&Fg@rmTH@jrO#?7u+(x30Nqr&VYQ~_ZU`bqVY(ySS?9V zxH$!hljmJuME-b~e4}$DrGEL+Y2Sy60b8E|Wmz=CuXN@OSjRVjx@$q%{MnjdI4KSZ zdlG!sRRBUrL;c({Wf#c=&N__dBPhyJD5%l9?5}; zCf^N0e}5opNlc6u+kblZ23QDnno8v7zJCuoYU*6*wO$nN46-N)8mZdl28_ZhlB3U5 z-!kse{mFaKWCnVj0Wyvj%;w29wicA^+Zm4YP+kqo9~%wZD3!dIq?aAj`6Mm)LMdBp zB~cY&Of0u5W&lRJt&wcTm){=erY7&Zc2D*H><=HQ8%5$x))?_>;>{ zN_(%Z1v>+TI6&I1nR_5ju*zAZ@4&ejNM!#kAlz;f*v>W}%D`06o~ ziH1QTFnjH+12$*P4Me}Ce?Jt>ZxWE?N5~Wb*E=Ku{Yhm<787$|Z?Fz>9KzsN7(jA2 zhiuORV0;tGOuW2B*nSUN={6vsYeh2PR>^ialSvTUAGiC&1w}d}Op9?o3j$E+7EvTd zS`AH&?gn|<#DyVotVAvfosR*T;T0{;;hAPDY?FQvAmtOZvdVQ+B_P(IG#E*(9_#|H zOX`B%0_anKdQTD=DRf&>16E`&^FJ>em%Dhf4fpWN2qBQz zEdM!d{!k%uk`D#MdgoF>nhx4^L50OvNBdGGT9)F<2&n&$3p>kz-rBXMs_zAHJK8inCDarDXH0=XW= zZME_*ss4G}73WBfe8sXC;65!r@5MrMWr+okpnA%jL8-I(-ganUt}WLssk2V@(rK5> z0j(aI3vvOiCQte+i6pICJA1BP&RJ*g*8VEb{rL;ObbpnSW{Enk=lH}Dm$bI5x#1hj zYs8u-%Q9w4TvK)KJS6i0>yOn*Zit+?Kc+FG)>y^LqHQYr0ndu-6m6j)$%+rlg*1XB6u|v!;H1>Pmhr!{x*yJjA$Q z8TB8E8%|qSlynI#&FL414;P{r)~&~mBuO^=s#G{K(8ZY;je`6zC2ip`cKolCwrl13 zYO5ke^_i0nhIe}&Jy7#55MR%GF|*)0La4~V{qCdTb=%AX>`nMJJ5G>=uGP@5yg7+? zrI_8SBap`@@&@w-?r3)C>)q7T`q)5@de=$ilN|xq%Z4Z2$ErvU&qK~@{s63b2}?7Y zA-D3i0j`KgFGrVGi%9N@U5Tp)GUKh>sUEHcfn&WB#@L5y()Q<_=p_Y_KG&D5pP_hO zt(b3Djk98BKh;$4s~Iud)eKx4i}v1G7#NQF$T{ATyFzzYgKm<3BoeQ5oOsNy{WqQ2 zKxu_*2@rGM6rKGw%9l`jlrf`2KYglB;aGZXr>K~C&B#c%e}eG4te7-4l>Zl=5t&i! zp?t)hfrnInTT(4vx4!CWyVt?t8uM3=uj4bQQoREgx{9)Ui&9B1VN+PrE9z%3ujSfV zMi_3My0-=LPnEpr*fV-^1nhrZuTfk}NTHt9aK^3uf)+8oT%|}5y8h-fdC|SF!uhMV z4TL?G2ErAXjvFoVAAUg-dGzdHa=o^Colxua0EGwsrn_H?Y>|zr&1!-0>D*uqiH01r?ekTm9XNF_ZG|LCIkR)MO8En~68ZtS`SDPLA zX!cTJ#;^gLEtKOU(cH#v$sP zA-}=l8fotWjd!@3`I%2?_bp51)?6Q#dEs>2N#(c<4CN)Z#}|(Y zem$P}?fbcooygcv=&W;;{QC3A;e~*Y5GOo<^!^vOl^1O1D(MY46LDPu*w%5rvf*NO zwW@~ay1d`$?ywXb+_22bOeycgIJxhhtIel8t_HIq3eGQ(*VsF?B2YIAEo&xx^-Y|E6qCi4EWfQzzPe4Cgt=0*B4f8`H%r{S( z*)4ia@opPqvz5NYCQgovxs8hq!j{U=K3tDmiC(mmjmdH0`|c;5(Fl!$BHS`rY&1rZ)9UC3I>n;No+Dtn+Q>lu(3t>PJS2mbvu85| zS_VxPPJN2wN8Ij(3M?iKTW(%0-Z6ZW?dms_OkWn7#5e42B9KW;1IOZTfO(5AB3>CM`@7-JbF6^jUC|6_p+aD@|rXpjb=w{b_sUB;HfMTmO(GbeM+)oI%AF{ECaTdfB zCWFidPd@}#qK7^-!u=z#UKe{-uK~8r6bJ}l}JML0wwG06AwGIfo_C=kp6t|bnkfCC8|jVPkS4h|Z_6_(NO zw#E6ZVhT57-@UGXiGIQAR6t@25qBoLd z*?uKYm2pQ>ztt_w2TnBqri;dcT|dGIn&_2db-RPV$Y54eT>AXwXiwM(MSOT^X5wc7 zvaP*wyPr0Exj||Q7D>L?$mr##FZ=rqyAziZDkB1zXr&bzsyK^eUZ{NwlDHc5R~=w+*(R z)W>Qc-5@vAY2h=sO81)Q#}}%q9bghYOuFUrziL$4k-Xr^zMal9B+CGj*X}TES?;{! zo@?3j;6I*o3p^kWofww4Pk3gzs9We_9-#47nVPHcYs9K__kQqmW!G<86LF7+d9&3s zNe=tgA4YQJnEjbL&WdqAxgzl9^K7j_bpI}#k$ippgBbN8P=Q5~Wl6uJLh5-0A{fIR zhAwQ38;SLNVEsX7cXzX}G5mGmhVX^Jju3P!2aK{{8=le-nu zGTsNbxfk>lpW#nim93c?Di{y(wK(MhJ(Z5AQ^pM-vJ#;e$^ADW(VrAz9L7M(C;e|O zv3^5(GdVDD>~)xbjDrdRf&N8ojrs`#Hkk7-mJ#bv0{SW`1h^cs1JKHe*0#+8nPXYV z(O`dXeX5}t1g0U-6#TSjm);*8$|S__nrZwNS#zVHO&Qj*JD^rR3Z`3}6Ko0W5yZAI zVcAsC+n6PgfSnV49`Ie+Dxe_ju0;u15^&I#?t4Hcc*u3$3$lYugp8kI&;_; z+>M^9DG|m!jJZ!(qq45txV zz27dW7VIW1-OHAa!7IjI4v00dwy-0LYY-piW-hHu#Z(l^hMbh{qjquI$M`eP2Ca-b zE?F#N9D5Eej0`2^x=0Nz&)hZ_yk`H{B)(4Y8oo*l&Ve{WKt~~Ty-F5k77a&jSo?D; zz7%NDd5d^7Z55V%OnZDOnAK{jkIYl~>T^+UQ0?NXMUtL&ni$>n`HX4cUE#Xt{-Olw z#Lo^t$uC{0TldzVYx$E$n+(?VaHL%&`V%rzxS zHT4`Np<691hu`ldkF2K1rt3Aoj}|cssn|YHfo|k+u1>b)NR)CvD{xAD`x1{;Cms5P z*4*j|4Ut|UA(0;&6CTvb(#O+Mx3Dw-tk)+BLsZ^*`KaxGj*1ve(BGkjwy-QoEJlA@9&7$1torcq4b;QV^%q`slMAF0=>4GM{iwZc+fYNYI`TG|-*CHW=lqdJ#bsdj5 zT=PrnuyfTF-l0@&4+-9(&T6h3ng>JAh26=a4+-h8HZhkmsqlY*Si|dGZM7931?IO2 z$GFw2;`XDSPbP?8Dt&p)@Y}(69_yR<1zRF;=fY_&DI(`jcmT0r+nxL-siT_rg%WIB z#qWzV2AVarKEP*l{(7oe;tkfQb6UYCN#Wzt&++}a>H?oHiQZb+{-$?}6zvVsInI!= zXBc4U`|bn{x1XNa!E9U36=n1xrx^pOM6kTL9(ex`f&Ksx=Yl$~MM}|^&Px$5^;O6*_qTyZ^l@G}x5M8(WACUA zP~vTFSu2zTmfyUOT;5DGTfOVYRH5gdwu`(1J}^zg03ldVo8G!m#jlV9O%y8KQt zQ+fVGSDp*2t>uT?8IR_*x{quZJ*%;Q3tW(#u9X(-86_(_*KzgN-z4i3rGL{Uw}QO_ zGZiGFDOUni6b#IziA1#f{*5>XMD_L+!CK|wtUdFqQ6C!F2Ft*qte(F+S)vE5Cq1L^ zof(%Busq1E==AGa)#WAFn3!n00$J@h^z{d~xC3&(|QYU%`j3xnFm3vQn5)B|O0S zhB?(RXraQ8@jXH=o~y-IaoP;#qI8OmGE^+}{1nK2^i8!csf%@#o-v=Z?XX~G zTL8A%tF8t6xrQ0)zhh(@Bi1;=6sj3z8#g4T%l(f0jKuT)wx4PT*VRVhPrUalhFO?& zA2Ag{H?NUH(3##7&&OGZwzwb2PO#n{wdwwKE{uECD|*sn1%4HA+psDi_^^yPQmlg{ z|C>%Iw54W_B81sIT>3y=NGD(HYA$s^^VfHcpm*w$LU#b5{7MBwGUh(*q7w_>x=fR) zq$Ib-0sVj-z>P!OYc1(e9=`|3!7Bhd#4?e>K$Mj>b;IHp<^;&9@P_10{rnO+U#7KL zrYQJ=G(^C|i8I3qdvuk|&U{6J23H1>#G@YtiHotEK=@QugWV;YGqH_b!YT9KS<_=I zyNM zoLpm83T=}fIgr;E_E5Wtb0JuU0DXmTfHF&Z>)d&2B=#KTEIa^BDNPyBdVkJL_yWrA z%RK@rPDy!c#eAnJ)iHeY-Nm4n9gbI!0necpLK>=k>A&gTx%x5V##UcV0o=&7wBYJm z40qS8{NQ=V)UAGleA^mT5}?jeY*HkDR#)tz&C}SlG*hHY^_mAbbqtA|CHte6MdEUs zQN7rAm*>zMXjPWb?cUjjxXV?N{V2&e=Y5-MGP#YWQ;XSRKEJ<{wA2lCHbq(z<0LHj ziE@wqEJC9@8^mu7iY!>qFP4%z++{2y$9V)Cg6g-O`Y z>OZy|08Wp&fT!ShQ`a8`PMF&CG+-(#K#G_V1x*2hV`9eQW5@<=j{<(_I_b8uh*Y==G1>iFY}|?-jEY=At^uG7YLJQ~100T= z0HhBu3E~xi>W=9cqOrYjciwJf z;kMLA_kZo%-2{zKM9~`GA7iCw7g8{Caz%j_CBatHU@&Lyy>;2eJR@z^o*y~FA!+lB zkYrJ_Q(^KMig=U#GPaJ7&ol)sMv`GY>Ec)$#z5V3C!ozsTv~p9PntVu(>tPLqV6D_ z_ud7z&ID#asTBD=?tN+m`DrQ8(L@3K`{|+DHq;;DXYm#RaButz*wRxhpu73~t6N!i zxnI$|uWqeP^6kR+n>XbhfGG$~+fBpNCIi6u>gM0HyZ};XL*{#b(|y8x`3E=Kf+v;% zZCoSQZ}sdc!T%%yK{6w!El||Pw}2wD+~ez@Osqn$9-J7q=$zl8xcq7vhcpbWg}x2E z7X9%^`>l|9G4!)~i@SKpv0ttMmN%1j4mB5lV>nQ3I(Kl-9NEU*iDFh#%SQjOrkXX8 zWw274EI+%)cQgmOvkN3%Nj7}CHrgf11Jef*jHMqt{k0EPfhfVEWt@#DR2uO4+cQsb8re8y!B+g(X?MWdxW|Y9K zTffF~%2om`4t8d#!=MVR$aet|t$}F%5kI?DrWM?qO{*w>&U+g|x+z)W(I+lh@ljm# zOdllWyH57-J3|%wat15RYP7ObnwJ#Z?ldv{NS7}jbDhG5Z$fxgaDkXA?Sjs}3^p|; zAldOgiSn>^Y<5yI$R?j1z~FcXfVK3XfHt+y-*2H}wdvcDZa;y_CcmtXR(5Ld$XVin z1;S#rmlaeZ$Kg5M555nKO5XXo;o1IjL8XBgF+`LWVQXyAB7o(&!1#zA^LWR7YV0jO zKKW}(L>r56B|STkg>_^p!0?S*Y4wBKSl5_h)9C|2;@_zhncU1zf8oYQ*^A3LccSYcGm(}D6SHT%Yq8Haktc3P zz4JA$`tYK>qUVeaX_3Q6_=g4mlzU7%4hQv4i`rZ4@eKZ zNh0$QOoC`^|V>0ObZWn3ohs{rn0n%ZF=K z!5dP$7pQ_XS;wBImy>EgESH1PkJsfcDi< z{J-hqf3?Pc{;OTZzffz4xOEi*vNHVjtc95lhFvVBMc)mEg3?OoB1(F>ByeK7b=*!0~Rf*&Z9_ z694>EA2p_AQRi%OqgFZVP4+hx?lT|oGn|W)C!=${PzpQv6E?m|$zTs2n~Wkrrp4cs zCUJI?phD|lVV)HY=6KsMbMI`d{8*>AMV?PUexK2={wEn{U-Pz=l^OQ zfP{b_pt+}u{%al81pF?qgX|}lI4p|D7alkTJo!zR_njQ(e+_L+x~(Mbgk3sc5ba>h zaEWKCmH@Opa}Lh+GFt9!;bV9619c|8l~GTykm_yuK_kP#K7h9>SSbIOghX56#y2hB zBi$=CTWxpAmp(DG5w zb0$4{rwaK@7d1}S$FDykVj>4tNv}*H+uK0U0#~EP-( zWc-(s_jb-YC&UZWAuI}Jc%$XGsN9H?gS)9U{cx48oM)gl&EktMVkPyiZA2yx%3CHQ-}fiECm3 zSL}r@5$XdZ)XFYJl|wZbG+h6?F4V&fKpDLAB=ELvT<+4qhelA73z6f*@V9Q+q={Pt z#o6}Nm30Xsi791F3ij!hn_QudM@izh2>LOF@LSzGT#t?PM6HtO%0ZEwJxw*X8znD#!9=?RP!hKC?RW8of&Wl~G%_PK#o)y!l0EAF2;@b&|j zlEjY7-IEFpof``B#O$54D8PzBB9_UJ%tfpvYl3KF=la9=otSSqu`D&{cPqg#zt#2i zaju5SXzg>N_Ekoo@37d4yKI=CE?;vpPMcck-D~YPj^0^PDOQsm(o?0X_#(Fe4o$R@ zGY3*q6<_$DSJu87ovKu;Q($OczU0d7|0KH?8r_}Vz4&XJynkj9+eFKOE7;T;~voZ@A}Yg&TjD zNme#E>LMYhdznwiUhnPBl>mkgtX$vXNN#CV&X|j3bfaELv4b}J;EEA8#Eh&sC8^lP zd#I```&<9d(be^zFAEiK6;AGl!WGL_M{({@IzQ#DlFQ&&HPTJ~K`#5(V-Nd-GM*ke zSjTrlF<>xQg2a~Nm)+*IwDf*#VaMds<6Cy-)=v&!hv}?T!cY78s$tz^-3&}(`EL;3 ze|E2YlU6p;z{mrweDfY*M$nHd(7TVE5_ej?ShgOjVE@MPZ0%V&=Y%JZxS zV%0PJP?|(&s(S_VOhdJWba_^M<&&=mSy?=8gJU)f)4YIC==H%ZEy5n7F1+da$A{X-zMs@Ad;H`uy>Y;a>ERag)hECF^bZb8 z4IyMMkgNo+GMrgKctq1d-xO^1MB6eGsD&Q+i@eXKrbggmcR7n=3rO8p>7%J~1AfR> zUiTN9ia~bj@A5y^jLp=YHCZn+dFjs=s{YgB@w)uP3*-qr=|#@SPwhfzy5#KTH7&KU zPwn!8oNuOBo{n(6P*TiXu)roineXMk_sRUwG$W5>+78cl>73cH_Za)2wJUE}W%T(; z<<9p{P%7zpHE=eBEdd$k6Po9m`s{;^gzH(es`&O{9=?#+*QIQA{er;)2(f-DpUuRm zvoF@dAmDk-b__of{)}U`(esARdN&LN4l6>j@dGH)Q zCy98>*a@wWTn)HofRmXQ$&CA|I#VEIy1B(U)hKyb>eQmxvx1E{x_ygJYA`RZ{U~x# zYrR`X^cG}q9+=UN-z5tzBB+{3SMhDiP4>1%;`#kl9TD`wy$=A5&@$1|P{_Zv`h!OP z3TOYH{5AhOpUr<>KRWL%J7RQQ;4R^~IMOAY{!{b@X&BWyk2hdSc>ez8_uhLSgW376 z6t2D?ce#=c=9*F4KV5%jyT8Y1AZB!b(>b9{!RpdNM7^-(6R3R+*}G&h`UxG;$X^^iAHIj^Vkv-NgwL zxEn%Ro@9la*dxU4TD+@X{+_|!>Kc%wEu4i63+M^ov?r{E7t8wPIwySN470!cw8{6} zvkHZxp)j=?Jyk7{%m71=@)`JuI8_H6tze^(o!E@v&U`5Iux4HsY||2pqV~bp%@`?u z9poi4l%+y?jKQSfFQ8EtQNralKBDABkWEv$DE?rf$&B1n!gfO{ zu;ggkJ6~zsn6%&e&o8L_iwuW!)R*w z(0FhcY~8>|YM%*1jf~ANTrdT8&6;KX#(j~F=~o&}D4DUr5?@#BShmnbdWhV8RpeJ7 zVXM!eRw&073lmwaDe1AnY@b&GVH=!_ax<9n4syaR%+elmR(z0nE}?n-ewC&rm%9TRcL#bvG$>LXN$>Kpyu(`n#oac}c;0#V1V(FAz zwyK5n_-lwg*WCA;j-z;jww5ws<27J?nSWPVTap#Hk&7`~>l0rrdL3Y^OVfzQM?r3* zX$&W8bu)?$4|e`oVFISr+?Eprf{$4leT}5Q$Y#*F>~M#UtmjLW=@TYGo^II)^xv9F zUmwfTe5I%Y{ZtHRB3~=}Kytl{b7xm|FO>Xbch)*g;#QTW>O=_wM8=Qn3E8!gg9^ai zRgoCh{J}eXyHoS&iNh+eLbL&?z426kJ$;d$|NWff`c7I^=8@8hS{+V4)N?BGUp5Qm z&>;$@REge7sT1|Q>UpShUpAM#R zT8hDh4jtv=^7z%PxE2sKK}dcgA-grOxtWer+c~NHJ>po4pyz|d!;H2=GmVl1mEa)T zS&HR1-2-hqp_#$${&>ea2ZooIPrnSdo@z|F)o6B1^^)Pyb{Uezp(%rK6Y%_%g>!cl zNigWMg}MyySFfBW{9H?)iYf`?vD9nKmnSxhXW}GvhGD0F?B=|PjW}<&aCmhi$$RJdc7_yXf&ozxybZWo~j*UUg;fYYAd*>7l)+m-yV9=rt7g`um4#Jj-7+Q3oa(`pAl> z=p}tc;9p%UiH(^hqyRlpvMA2#xT9%pwW!DW&cbu&?>?eG&wjZhdVng5xLQLBb}wly@dlhO!RPxdGzL=@Z`oHF)IKU!Wmr9eHY!zZ8b3U!#D|SRPQ9fBuAF@& z#g+19?NfpQpHG|5mQ{ADo0sAt4r4dG>U{N6k0KLa>4bUkde%ntNZru6X?w zkP!cu{rNHR?nW`PULDDE#Kg+^16*j~^|gc>VUNQE4+iN4Ncu^wKw-V)E69an{HEn` zr#79eo6W`dQWlpXb+^8aStnw zqet;L!?y^ql0dWXoK-2YjaFVHkc%W!KUZG9XwlQbFY=R1U%vWJS$z`+uKf&_{(4wD zne^QdhV_3plC6Dyn6T5g(IZ|>^) zwxi~4r0zdg3MhrM|8Ni)G=k#)_g{!Q2mJ!(C~NIv%Hlz=20Eji*j)GQZjUL&XWses zs^DC`0M@Yn<1vZVyeH7BM@CDRy}QNhNcRgTz(I`PYU$j&;7UK9CW57^i^f9&w!Fu5bh`RI{HxA+ew=z})@$imJBaN^J&Ru3qB5v%-p;T14%wN9|!VgF8d1B3<^s=?2x1^OZR}%Dkv1 z&B}h`saG5Vegp8U;JAk>=Eh8|p9XhQThKYz*|iaOszwZWCx`Y9G)-f>i0fMp3#{DS|+xgEW!erGp4amky!#gc@4@bED7m&U?;U=fli8 zGap>6Kw=W|d11_4FqliD=&#nuO=izbSLA`KhGgUm^KjU=**gMXhP`m`_ zTq20bxQuM`gt07s)x5~sm26bgsvL6bjktK|9ym5Z824j_LP5JbZlt;91tStlEaAqR=6zhv;TY0~Ndip?{ zfJ`&iLi4}(lW|^z;`LBKptGD2f0MY&{$J!J=Ln4o3wTbxICfYvx2>89x$xt;?S1e2BJ7-xg~hxMn;p zOo}OdOv+>bk}SC809k#|r`=^ZoY_3&fNZGv1Th(;D|{B?eHzHq7a(B`VJyeMeDBjZ zMB4aenEgI+?&4x@@lUl#Ym_aCSYV6(4I#z&Jg8Tj3{yVjQ-d2xw-nMR+Qq}e&G5tZ zqcq9aGZtSIHF-Xi9M_U*7aiMEcjcBRv^89c4g3{Gk_R-;H_e9&Wdalu6(u$mB^^SL&7Z;U6x@ToPsLY&0yWmDyDrqkOthhg&- z6Z0}x{Dpg;gIOT4YNOwSjX96TX7h2d-}spZp;tNRcuViDV)4zG=VUggp*9OZu%-A8 zz79r<0|7HeoslC>pp3qyqCie_otNFZ4~LhtMS8zaG@kB>&=$$-uSIY?w_v$wLA78g zOrqfBraj(Lgo3tOxmI8e~z!cAk#}DD8=Q93E?RSS@ zCZE>LNtJP0U)Ru)m|)!)UfOD__oYWDaAkjycn55N<4Hj=`b!Ac{)K0acSWW2#zh|R zshg!e+|R?RnY{#{s^n-=`|j-)n?kb|(wS5xx-D`iNy5?QkR&mh-KpSe;gpd0CwY?w zJ>@0N=?OVB0b`kOhPC{S5Y;}vm!+AY$nqih=Ca+Sl}XzJ=(OXq$-w(!`vU|~uWz1l zhrK&_sCkO;l@IBi4TI-8#R5>Yz^C*)PoslHZE>DfqdA>{f`^7#kzT%4!#aEp?9SLh ztUEoIgao7_VNu3(AZHD{fq%55{|h7WAMNS?$NhH#D8Q*S_yC;#0O9+USYun8XIovT z-hgz95PRZN55b2Lyx5guD%uOb#S8L0!9_%%tV z0|YX#@s$#@lvWcKG$+kRsf=iCYb9(N>%hek4_J%@4Wsd?fVe5#@vmL4$!e&yVKF8b zNqu;B!v8WzRk8oG{k5g2>r!i`bkZ3ROW*OW@68~!=H2NGKw>}B9GieAH*af_Ky$p? zUJYrREJ_rZ7WdY>qk+V`vP3fuo}y!Mf4qGhcKib##47pGTh%^mn<#JSgAGTHANbR~ z1@8iXk3ut8wM$i1O+x@cZNZ&efgSVC&!$2sOVLF(cxSg5x`DY`E_`=U|8qc}%71Vu zcb~8{6>@-?y~%N0TB*=0@xsx4YMtNVsQ^`+tROilAUU#^u0bGZrC{OXZ@=8bii*>9 zc$8>L`DCvxy+6=8dE%z=!7cvIF#|~s$Xq~sp7ZW9AWo8Zp=?0ZhTk#ANURjL3uOg2 zL?p0HS))w2rM$Q%TX}4|BJ3Ham z_Du-4>G2tjL`1V5>Mncu%b!V=o*NmI0lE@sQ3T8iDo*v=P8r)_lwOW%G#(+v>Q>ez z{r4U{#AV21wXA?HID=sUBovpP0oh#&MRy{DhC0G3#-CG9D#*_QB5*FtxGxB%`#FG9 zBds0ZH$h*vpxJ;`pWFrK$iPPVo)DI~1j6nW3LkmsctOxqiLnd{pu|`M77gRYHT@3# z)5x*Bd`*9UuEdpvpK;x?v>y+p^>v=3tvXK~(j3jrOZ$i_E7ZufinPwZWa0SFsY<5l z*{Eu%xIso*4zhtiR3{u&3t@u)>U9M@IR}ucs9sW@825$#HCPsrxcm?|n{RW0%gkJF zfN{<;#Cc!^n~n`xNnak(DZt zyh<0d>nP2z1}Lf!duO6j+-+NnzOQj6m+j8gsbG0R23Lf+S=jvoLVi{-91@lbe8-(0 z<}G<%Uv0Q;8Rdo8>7m8bIk?y4b#zk40BI(|ve`{yKT10y>rLeq%NnAVGZb!E{C0up z$qG$<=(LfxN3|i@D+@NNPB|i8&=6-YM@CNXhK}s%&}!iM^GrlMd#%izO15JW4CI`CR0N|=roM^Ide@`)jK-8R_`ZMcP;BRz-xI#+NJ{wQ2b zqqi5Rv7#?K6~cFT$dUzNRYbs1wZ>Xo|b6s!NB*sFUt$Pz@(`-=#d47&&OB zHC^Ag(-(u-(9+*V)Z1$Ade5DLN zTj5>_XVQk#>1`-5Cou)eMDhxXk*3&;46ENB_yo7v2YrWV5HRBb3;!1ll8tRgfU*^v zB@fyYvCF~7%U^B!Pb&fjQ@PKVL{se{E!kTz^>chQEaU(dgq+eJd-W>!%&l*EK(g@J z_Ug6qpKdQ=DVY0<{19}0R+N4$J0gpe-s8X$1ag8$Fldj(9)JLCd zQ3BDLGNiCDE-KJ_L-4*S)oQVi@VX>rNxy34Vnjqsm(pBrh#s2!&U}5eH`&Q}1kGqO zn!U8ZxU%u^p!{JwY2~`rmZIUq@s%M9#X$$FU-f;%TcAYH=Auos(>=87WK>7WR z4^}8pLv~w{<_f}ti!0(ckvY_IIWL;Sg6GILpoi1rjo99~J$|p(#Lc#$h_j_}w$Ij* ziUkXWylPryQOLb@wLYQuNw3oFSlR)qH6Kx<^v*G7=tZsOoRWhqDTOqtjJJr0(_VS; z;D)4Ew_aQu+m{QHk_Y}=0x)_T7+Hg}XR*O#57Ky%?pUC6{sHy%@6wAyO`TmFBAt4w z8lOfUYrjZSkxPqaz@(u-*VQ$9pQf>-(B3-mT7*SxIobRDuCW^Q8UMy*+x$EF4B*s@ zFy$c~QE<5%GJ-3(?az+{4L}(J!z>MSA?Yysl=?n=w+*lu{FxP)PW#MO`x#Nar_FHE zKlcLjez4gn7|ks}C2S^vDQn64zbJKG0W{c`+py}ee;$i_1RL|kM0H_7OU@JJPWktV7sGb_Zqnhx_ z>e6Rdu2VjIo5dA8SFXUvAttsb^IqauYgf;c&ueEkjgq4+6%>6JIC zcm@Oq`B)sUQ{AUD?lpv0uFY^TVTEabs7j^V@=UumPvq&02-mCih@2TDu3Y=b85H&e zcyylu#zr~d6(^|B_}9}pQLaNf8(Vu9l>#fIl-=xKV10crM1?DAqqq87EFvF%y>|6R zxAaiLSf_T%hhxM2-S*w!0TgmqvpPx3c(oxi`$xxD&TAxQKI1pd%FwG_G>nmlY4_m7 zrk_6A7pJjWM#cp5rapUPrm3-=WdKXk0kl;5PaWx;WrMtyQ8yh~Iln32)NB3F4@uZ$ zIeI<@Qp(pCvA-Lg5cu$=Qj9CMDH{8F^vEDL%0$6N2iOCF`G~Nk5S&O|plk&&L}M(8 zU?9kWOaiH|0@iybzY7m7V^^k-4PJ?)cUL7zR? zlsQ+(16M;*4)~m(k3rYW0X73ZW~D)epu?2LflmWlEyW&aN(6WsGXQuHwiI8UgL&|| z0-kklE(1upe(k>3#Ygwp@%BH@1K2LJH)>EML2N^g{LBrW_1^8VTu*Sh--Bzh-ZYI@ zBtxiJqEMOWzppd0^hC&j#;9=MkH)A(Dl6TWQ3lZjhFd@q==?(xh@PWZxh(cCE{py4 zB2f0bEW^71MPOuD!`7x00m*kNU^$!ntEoS0+kmENPluH4!1p>YO{o6iKt6??o`CY+ zBlIx~kof?{QH?6cDo8*#*TLFp9IQ0Ho8@D+XfBRt)zJoIsJwP@R(OV(Y6ph=tchq1 zgCzsQPIsg!N4v32DTH=&?5JvQx{o(Lg6=_vrw7YxoTYIxR6hv?#&yZ};NvaabmcCc^`R!;jP0puyPx~f;gc_O^U#)-b>nILd?K{Q7Q1Q6rFdFLs?hvF|b^hczbogA)#xM4kZ$$U#d2v~gc+X-gdfRZ~ z_vTZRf+kSyCZ=@Htlm}nS}!NeSC3Flg&|zIA5c-B^SnU^)RTlkq#hRM&+y0>PEGKp zWO3gZ{BB8xY2G5ON=ppf|?678`m9N8g^t@$cbaQN56DT#es`UbyOnXd8!%V zr@1&oX~!7Sm)DVN%f$nW2#qjda_%+9aS|Fy$;n9d)>9Fz?ttI)GFL-iU+U5x&qd?q zkj*LC6aIcfafOwvJgBuwVm_+1k#WAQ0T@fTshFv}oQ<(rRAwQ^z^rpot|az%@^G2BIUhGb(N4sVqyvec)0S4%(o zA^%d2YH_7|`UcaPPWdujTs*Hc)S8iElYwgZKr7SqlVfFNyQ?`S_!snX3P{KnT2Ku8 zVxu3xC6+kgof{TMk?2yAT|(Vzv2!+q9+&wtzD=~Stz_`)z%GqLvv!1GXuDUzkvg{O zD}IbbSFa*yp>MG~`J{x-3vs)3t?847om3k4A@Qd3iWOAAtX{6m(MRN0K4*TG)KNfv z_x6XU{VZEYA>$11LWv`$IudtEcNa*_V9{%DoDD_3(>zj;9h{VH-F^Fc=f zAOMM=n5-7)F1$I;jW?jjYw$??WJ#SB4+S8CZN5|K z7?L>oXi{3VoVJJ6@aclef-DOa%gA_Q^rTe>{D5$1;L=&Kv%E>@Tw|z-St*A-@_M_P z#n4@$eClaDfq}A89`dLo&0*ESKQaaL1@l>D^&Hu(wD0OIn0;4bFrz zatB{S{HU{8Seo?k5G=SaOjfRcDAK&3H@(BOq2-Ki$-+|Df8Q*41fR#Ne~Q)*nVIFbJv@t29Oz;${Atw!)sz-IW z%<`gXyppt|)_EhFx{vI6Q}^}!)SM~0!W?s}VlBc}*i1F#NsNAoERB_l&Ilhs-jW36 zQ5G7{+C9k(=ZV~M+2&`{H?ZQ~Cad@Swe1vx;#e$2@`h>6D>ALqXlxC=@9CqM&m#5Z+or&I!wfw?UTdTK4 z8ww3N<2eUXi)SjB_9$NA7O=?$wJyBW3M02@uhW%Ig3uW=50uDk^umwH(anD()3bWt zZm}oJi`^@S3b=$39#d?=ZUzXfHC;jZO==XHdpip!l{zut)Ia?8xr?Lphh5*4q7Q|2 zR~$-dc;rQcH{8bYrkJUe4h(Y@j@BE-upnoH7W*ts#gr=>qpUv*m1~6GwSFc=)^DIK zJ|j_VBvqspZZducITv9@gL+ygTvIC-k<=@#@VxPH_7SR$(l! z&=6-;+>dKtHq=mJic;`5_D3ZFjjwwnkAnvgzA z?fQy1q1yXDRbFVQKq}&ehKzV{jyA*3jyjHQJl-)>p^yKAW1;_DL~?e9f2Q`MKdW$P zs!0{(d=~%y_bVHt=)3Lm)kw|Ihv~!_TvY$T@%c)#x7>8t-nGe`uSR*PF{fELd9zcm+kbwW~FJeniKf?dA67Ryh^EfX2p?gNBgl(8xfJZ@u1?gE*+Frtg zsjepD?Y{M&NP;I1N8k5dLr>JI++K)3eGA%gJQ1E^%>{;NSGX(h&(*%CiBIqMh0#)T zOg0cD3|Q&!(jS`;YQNnyyMm^DimpmS8}&~Pw7X2$oF;5NnVM3Pewh&P#Q53CYYrJD z_Tuv=X#3p|_ia@QOe|Yat74>MR!8n#2VMVl=QkfdY;n^nqVqWH+-1f-{_X|}Zysct zRr@S{$}X(_%(UGznp9O6w}Ly>c}Lv^PTt^-Y!pI@q$gy01^4$48GmG=jQP^A=pooo zkV@=4J{$$I2F^s67DgFXl=Jk1F5q_F#gGCfb4JSM2{zSB8}GqlCi=?h7Yt@m*Zrz`|;V~(-6 zi%B_)OPH&gM_4{>jgw`#z3;3&`%L#C2LIJz$DhraKy1?(& z7yvsLlMIF*qqB#C^zP$uYRYx)4n+&TnyeF#p7aof@C_Q^2A92Z9w#xor}svJo@dS- zMuypdUO`Z7=wok>vy{6jy_;g)d&o%VKxf5jL2%$mV^jC48TZii(b~~%)1K^`hMCoR zzqeke(mD6!4C@T$vB!m>M|sJ0#K3X?229qKsPY!J$5}!8FRCI(@89fST>_OJu0-^b+pen=^}rncgI5f z35nceM>4y|58Ty2Gi^`ggX(I%qgB<_uiLYskyY@s(o-lGX=TCW3g%V{ktlh77wY3cIWqg7Yj*GNEU)TfV5c$CXCKUB(K zIw+CEct5e-b*(0e2$m#WdRpze`#EwQ#*G~!L4<3S9=lySE;OYyYGV&808;amunJmzGnK0Ezj5$Z=`Nl@G0T@}hj{uWBI#F4yffSAM zSKN5y9IT%l`g})7*Ls3DUV;pKo^NF{|LQ^rIWrq^7xG$ru&i?VB2_u`Z@yZ$QM2$j zdx>|FoN?@b){YCW=kjA&M9zhfTtNPu-1i!wt?=^0@t_9NTszp**XanZ_TsxS`c6x? ziTyXHuWL(BKU$P9V*@COdp<_MxCZ$6QFAz{pADiZ?v_wg=f5RmuLh_6yzGhC_3r-U%KWR;+TjIQB- zKhDD%$^CsWFJ^UNGm^HA#;^S2j~?#|dkHMrwxM1czWUzess=HI**)p?-<>EB=}Tve z6&)<%t9*OpTe$W-;VBz!Lh4mXAN^65*giif>I|!@AKZ9o?07-Nvvb8v)l;c9{GB;# zW?)?W&=Z#%wz*(vXNnj&od>ZnC3-SySlMI5A!uF_OvE0knXhIX2YEMNmNK9k5?qXGDGy!uiWTg4SR?1FaJ^=jSJS7%k8CJdBja@S6{)z}n1Sj zptETtQ@}(l?1rEWFlt73Gxuaabg()(D3STKr5@c^Qa!XEc^})oFhlXtjZN+zLXBdZ z>}eU8+8CY-Z7PU+8qqQjhZs z^B9Yk2Xe;a@9T2!KKoWc@Q{uHo3N{KXN*O4uUQ`UGpgo%5)pS zjvUpc{8&!L{3z4;PX9ob-fnH~Zn@ajNq*v4UuFh4!kqMN7}CrMkUUaeEt^$r)E7Ld znAFeb9Owu16(?Nu0-ru8wZF|FCk{-^-xhJ3y5Uf<8J2Uc!eSAhzVKch5&2&$XYhOe zJa(PL;*tBS!9h2A&33WeVTJODeHQIz)4o8Q9 zWx;Pz*aZ>K#*6l$vVo@+89Xct#qjST$m8p4O)&^tP)$Y{ku$fT9sVb_1xCnI=RPXn$CmbgM#oDmx796-1JY5 zy0|BzAuoO((o&3mxjt+PjP?+vjz(hBb_t6(a=Y86_} z`&qawn`R~&Hk>6szr)6=1tx-9wcFSW4#B(lD*1ONz0?+DXU5!8VB>v2Fo8OL=RQEu zu)c5sQCqEkGE`*oQcj#cAh@h>7XES=ydK1Da28cSPsz0JWv80EdCy~H7QvFWyVCRU z2PlZX`db$Zyq>MGo9NBcS4Zp%#Xl9bUZ45>Tx3XQO!I{Rl9o;}7momE2QPWQF;NFQ z*T{>sj_38(Q<}h#+xfR8PY2YdNt!v6xbvd>6}|omr>^| zon>j2#(^T2y#U*8Y!2}Lr;ts|82^Fx0V4SCr{E7sk>JeRN86YdiDl(w24W89>pCON zOC+GPFkw8=`*Ast+&lg=kVLJ8z4AMbP6hJshhXy*c`5(Sfm4-=T$(7b+yig+`lSOu z?mr4CZUBD*ThTub{F<5@T!GoqrATO+u)ItQ^zZqNeQQ>Wss<=0d~^E}<&4cc4gJSy zX)Xw{#|1DmnB#e3)7uBwtA|Qm&yser`|?Q2Vs9XU8mr_Ll%trbEb~e&@j#g9F$SeG zH={Y)OgVH%bIE2kN?2n!O*<@}iPO1V&BJ7ppYxz8kpf3|OYVM$@P9>#ZJlM<(d0Dt zjn>2|PuNo!##fXEx+pO&n&JLF*5zy13CHqcLeTh+(L)9{sELl8zAs8I?O6=EA16K(~!pJ3o^9&ziUyJw%0&2fFM#7*!Co#-RH>XDj3z^`GBV9xqf zZ#n0%DmU8cnBcV_HNKMy2UK+n!tI4<6-$3m^UF^Q2`5{BGTEN7?Y6At$o#yX^?fj}NpV3Y4P-U6TWX?W1(O5fY6Uc*dB=yCQ|pCL&AhJCxOeH)_o&J_gRVG0Ll3mpporW29xL5t6exD~Yav-4>z0 zt5T0DPDmwAmmB5aVhNV@!S7j04{W^EN>hw2Ur>{pG36aP{23-TQNEn0&yz49{+(j~ zxKk?n#)g?#jW^$+vAVI}J>`{QEpq~aZol2LrqNAFr6_5U`AGbSzogZ^Tzt~1sZdK` zw2Ey{w=3)B&UPO#av1yN5>i(bsTtZN0wErZ-6kDVJBww0gF$Jod3%ls+cPC7aQ<7js&5XU^-zqA3iMm@_hH@*vuq zpy&OYIeIujFWRgab*wwwK+E3fUZ}ZH?=NX=Y#d=Q%Y47=W6X|;!y1X^&tEgK!t*Kh zQb5CLhZU$Bue7J_dSG<3I5W!EyZA1_kM=;JxxDdW&*V~&;w%~r;l!jv2}A~tgeJ3O z`COZWsRxjnW}}-=XCc4%{hY<#73Zc^8n9T!J|@injH5j5oPJ}y1Cn$v+vtPxbaRcJ zspN{a2X!2Wb;1DQcT)USGxbbAJ+#O`3$K3rzQJT);cqjltKRonUQQ?f2qcy@pZi)e z&;=5dD|SOubSZt(+K>8PZL>`a@?Abr>+YNQEvHfHC4( zPxFCrX#pB`KcJs+PuBtvVPDOilIoA%i){(R{Dj@c=sZH3Hr)0KZsE_Yc0p&AT`_oX z^|sG-7v=e#Rzq6IE|u;%VtCWEhkQs}{6M(>C70ru)pyU>(A~U9#jC16aE{EMjMvNr z^!Xfiw0|q9%quyeMrqZjA{&}JvA1hc(6H=5M+fuT6!AEDR@H~+ZQ?5l$(xn6L}|26ld71EHE1 zQV*f%m7-FNWi*B7NX5X}I{42US?0&vc+D4%G741+`|JfxJ7_wez3|pBzxNSLk>rSV-U;7-6v=0fTXz>o;_&L|_AJN}DS4F$F`H@YhW^wS#yrvE< zz~AHt@8-GUJ){XH(CigF}C{KG>3=QnArXgIA4x^lcImI z2Po8fZnOB9Z6rVG#_*JxO`S^@Im5HPwzp~DeGo<{bw{NJ5O`6{qZ4UfUjgUSdrFA= zj3KMkXcv2Joy-oxKf=46BH}*WyWEd|+D_k8slu~C!8!b7Mfqq(A8D5NGTYRoC2umB zIVerO{I)XnDpl!yXhm~4FlSI5!av882c#AK{EcRkO1ntzomsp}&&0b54A1FeWVbiX z?!&E`8Hgdh7PCk+y!DH!3}JyUWhFrUbIuJfgF{)cm=6F+F462lP>M8%(pXSRHa4aT z827DmOpLzizp=`CI#zR$?&sw*^}BQo{1<=;Lb$zHda{}ap9hE^L4Wsz@3o!eu5)Ri zL%THQu9#`1|d1?hS|IVrssajMnuQv+h|*uJp1 z_z#bbRE^~2x+yflM{o&sI>VQrZscb4fAIb*ChKy0Tm=C`R$?I7&x85U4t)D*Bgelu z= zIk^68R%1$8G%?2^e`m={#~GcZKgsd{`n;F{^Ws-vj_y6SK`C07i;zjoxN2go5yTcQ zm*Bi+Tb%wj+t3=l?onr7%8`?*OX4gqs$mpfxqGN)9F^yx7R=J@m4^j zEc4GHXk*Oq_amCEu|hkx!5CrXslWu6MmPaVRH=4sc@-5BY-GLaNMfUC5VbZv(Ul<4 zFV{sk=(_+TvGr7UEwDDSpJ}^Tx2jOG>?&YkuNj~?x2Q&qw^K=Tr${I1sIe+r3BA&4 zSj;6+%|XH=nwU^W#hwn*x7e zDTLsjq=aVToHbG6ItuDy}kofo|>M_8kt z2Ko#Q*EbitL*M*t&<|k*UcG9+76v0hM#&M0fYsy=!=rh=VT4)5u;X({``)C2-)3tx zqFGK>Bf`G7YCqywq>r+iN4s!2G(fXp)5Zh7*#^^UwiM62?PK4|X~^nC;Xo2rBcGQsYY;CL%$y0Xr+kLO;uQm%QI_#tp5YBA%4QF%S=HKuH~5R+f3fk{*?!+QweF0FQ7N)9wQEKC6ad8~a4wt=iEwr$+;U`##WWwZ(QBG?Q zVN`cUEv{2Ebr&>}_c1cHk>ufUg+0HDk|~dRMH#Uo+Wu-+{pM>S)jCKTL(yrrhv;Si z+FRX)Mv-32oL=(@;h<%1JxWe60>p3O-fF=jc1>ABq!<-)Aed5ER zhZrq50I9H)y_8y%y?kq3Lghgc|BY`6;bnSyFHX3j4dUCT)$QJo5H}i>IBDhA<3veb z70bU`e`k?Wi>6xp6D^vVe?YWNi`!F zrC*d(PmGV8K=Yr$fARJuz-@+_3h24$s1WagCI`rHvxxi(&*Wvd(WXCb`;9uug0%e= z{GTd3wC8=_CuH3I^4S%ax6WM}HYwT#Tg!ds^I^Pv_ue72({UqNpoKTmF>7{-?plChzUs0ewWrK0wSDF?LU|0U4=SE&7e>FaBup%|Q%qTDp! zdv7VScW!iZkuk`4QNSpU=Gwe6U?6yei^gyA)wQ&&xF?orm4byj6NTw4XCjl+#$Ky> z`}2wS*MDCi0o^?@ViTqse$84!_ldu3W&wk}%9)CZfFhTTHS^7I0W}4tukkMu-#?)w zBY%+=u6nigMUpkEzjY41(paF8QpX%+CxjRCfpPy7*vFXWZGke#c1s6zS3vyxdovtU z0Y`3ofghg%gQDk^r$jP@}iD0d-o#Uk?s~ z@n0*9m-=AKTNkUlyys7}=YTU9{yC=Syl?=^2*Z5PyhwFhMcKa-ODR+r%`hv?7Wzv%dhp($?@N(OEsznq&7Pl{?TK_e_6dYiOx=aFtO#iDwab>F4SOJWIOr18@^KZ`sHe<3l8ArBpG z@JR#ByBb<#KFlKL>GhzEKdliTXDLc*yr4P!fE=xjvEGOQJAL7RXBBM@EVOlt^mxvx z$S)Z4?+{v)s|hs3Z4i{=tNQz<6R+0<+p!7OUTTkElwx5`t;K~EW}1_Rzhi1Tar*J; z(Ms|htV>((9Ye9VLb{r$uzfX+>AgL08P-sT>#xNL^YT|3<`zmrGSJYi)l%#6x@;p` zB1J9UgL(3Z=aI*Bv0V(AjnkiBwyggedzti38fv!?(MT}11}M7PW^~ z&DAUOZ>PtJkkRkbZw#Na6wXX|1>7jf_?C?H-|_e=|2ELsEW@A)3=FaShR5IH1MD7h z3&k6iLnyW&@s+>8K*I-L1+Rpzh$plmBJ5tjhk(iHP&^yG;Z~<}`p+m}O%faQe-;k? z7izs+s9sKVn1PZn*&L!wi)5Lr7qHt zZ1!LZ5knOXvpp4}78gN7iWf{R)om{p%RHXe#urRCM6S*j%k^3~h8%eY45mjxZ3b>1 z|8fH-KZtd*h5|4IzIFv%Z*wm2NblKCsKpMSHsw0YNZww>D^5|(d_JDVY#83fBNi;z zddS!#KpG3dOG_SoCA87B{}o!X8XB!mqRxmC13x&Jd&fv70u7Dbh%PWRHi}@O(qt-| zsrNKN*q(4(o6RDXUz&bXT&A+hz{hKPcaaowN)i@*Aza0nHN;*?;~a#Heu4I=god0m zez6^k?Ycka(Z|hNJK63bUV5FeVy8v`Kp{lZ;MXO?&^X*h?Xs1K_p$iQ0pyviS2#tqO291km>Nb2K@30@s01)Wi&0*M4`nYOZ9dUZz z_)k|8FAOsp2hhr{bd6m;!U;qB=jIKp*c~uKt5mZyo?5XXO+8>_UWsRhHDS*a_h159 z50!OZiw_JnY9760M8j+&*K-gTGzmWuZxFY^Rx#!-_OTKeqV;pnZ()3qj`)~7?RqqE ziam2m?~lmykyq6p^Qf++2c{+K*~(8$2u)Sq%B>jM;WK~INB(M_;oTdP+nC7w*p7te zivzpbkxbu6_6@3W*B&zN_lK;`W)@8(<2cmcx-KeV=u#zo8X~Bz-x1r$ib-(k`F(pO ztRI-iMN1qzp)~FY!rxQVEx8lwE4|AJE^WBf{jNrDL0HVDHU32fc(gcX^z)pJ8P(U6 zJ>Kx+Pjb^FQkpsTM&gc^C%i6BO=AY3ot|Zd3j>oZW@G1ixi&8AlmcD8p7iw(EZO8A zT#N2+dWX-X4=yN@kaLq}BHxXwMPNEYaQ4PWKc-TtJS>k&h4W2zj&OXx7I!f~1_F2f z@lCC`bcz0NHmWe zjVgk7@Ix>B#jt^Y;%u9z{XA}6EbdB@kl8tVIkrg#mpk7YppR#N8YQ$ZDn&R7y^5)u z>co;&jcxO0S4Mfb?PWhxO?V+09)i>juxewxoxf|&u~))BKQ+U#^&cFn;S|=U=We_y z9t438+xb+sQ%=UqcG=t}eA}V)6;NVKa)oashjv1u*6p+>*IZLyx*iAn^T@X|-sKe* zZbGj?m||*MRCCjG_aHX^@-mWn|be(#Wu`E{kxsAg_D&TK@Kx zPJzP?A6Qfa|6-b^3Ysw1D}C@lg*SVzBEzzl^DdKjNX)bqq*9XBCC9t~B^CvC!wlA% z1?yGEls$CYxJnSAm@5PHwO<&RF?m^Do?S+sK@Pk-xlK(LS7L}_cg3k$$GOfVU(XRb z(BoKQ2a^E9;2yGugwiHJ3>N9bUWlxx`Y~-Q(D7oOJ3*juiD^|DcUtSS%d9;lBp-Z) z#4&shtf;3AlkN@0cbWx)!m6rub)-sy^f%Vq zIMgul=K~r<&WMT>;jY$*$Zm(Fhxjh4&Zc)eirJ|T?YWWgP^DInS?w;iZzdJ?oZ1@m zSEyN>$geTyOi6YLY97U>10NbRN@i~vq1f;+vY0=zFeEYl7pFH+t< zg$UAL&cq7V?zE?uEe!B`v~4NgzKfLwMP#+|*{J4%q7x>0v$@>!JRT&t;(@U^qYI`J zm9W>fH3J4P$wh2S9FVs-kB=F^{1#%|;gk~7nd1t=DrxG=!41UuyAt?jMoFqtYt%X4Rv}1SqMrOO>G;1A z^8X889lV}c>B3Ku@Q%6Y1pTd9?izz$v?PGc0@qr{5rdsf(1B&>L+ZS z*uKcxe6!Bn(~}RNeH7V6eA^X;umh=Q)m+c!_e$6a(HwX(kd#1O>UWU@T^w$oI~N1Eb@w)&-a64RjLr-0&-8O!_khDcG1^t7*36{ue$y(^FT%%8C6$w(-0q+w{j>hCqVC!Ve0|LDq4H zcOLK~roQ`MhTT?w4Z9!zH^c7BRqX@a*o)ovzqCkUW!m}Fne;v+< zwfjg*=0>>j6|GE@>S+rF%FVy_2|t;Mb~#<^$5p~yS>PpW2U*dDvqFYH*rIN-5(d5L z=3tSrnPtLUUx41RtM)1G=*+VdnGRObo^;c_?-N5nXIVGZOpkfd*3R;SaVf;hH}|l&k7;f$DM1+;uOq$0&vf_Tm+Z@$oT>%cPp;=flp=KhICDooZQ+~&2%wRzwxbr)}D*Iz@d z9dV^W02xg>v*{DGlAR>xz@QMWd=!X7cQxcIy{oYpjOc!@<1POr-6n7ey|aq257JB# z6c2ddW#YVHJC=v$Z%L6k81sn^Et;==jZ}^x{o$PYj9_k9M2gq^@!KauJ5N`J7Cbw+ zt%xN(Pjy!O@s@dPT^a8L&>8tX9J03u#=m8DhVRSzNbw|C^4QA{H3OSy$Nj`|)_p3D zzxC$fb?hl$8>T$#=)srxe)^*Es?v?@a_-kcan2^WWoT&2EaOP_@L`(I?BvdaTkTrE z-@lIv_tmcD);M}(b`4{k=_j3jYEOwg@@&vm64NNI;Npn6rI62?B_iXE0Wm@68qd@%bYrRns=xx}eYqRp6hjmw zRC-()ZxaWG-vtJlqYSZ)0QK&^3OdLO9=z%U*a;5o0-p0s57Z1dEW6L@)-)WsI&g`j z!ofoH3z!Ecnz5>Wb4Ns%Q?KgjXWd5&?dQ*xZET1PyFnHW`IVqWb%)iqCbIg``*9L% z)sqi@+|)_LtsZL#(Z{rX*`(o}O@^e|(U^3a+uZrY4GC^kLI#4qzI=4x?B=D5;z=pR zpdz>GRz;GQ!O}QB;DxBJV(Vyj(0xuRN$2l&Kyk?n#b`|h%_LZ7hA&Dz1oJ0T<{#eW zr6>3Qjen{*GbnJ5hNU77yMZr)X>sJ{`e{P(mTJk-Fzb)v!SJu*&;;j8bC8(#&42Im z(tQx4L8sL2lN*apG97JD$+H2XvoV1#PnTE$+Ay3{I@fWEZSm41>D!;0nATXZh^*2A z0Yg1izV79O;31tzHcRT)!cqV94m<1U0frZnWtR zW@Xi6guMziGu6g6QcU|2Z~4BHHzc9RR)YX#Ibx%o|38R(>$s-d|6d$M0YOEjb1Eq* zjnqV>r9lLQiKsM)fHV`4ju8S%s+34frE8N`k&x~f-5UxF7`x9k)cbRPKId`H@9{hJ z{lkEFU)QVS`I;cQUoz+ zK^qIhkkjrmmQW68v=KXWK@OG=M@bB+MsNIt6HM-3(lV^8l$%jM#bAeS#)v$SkxA55 z>lKQg^}RQb3MT2TuI7AVDv00mA;qA_QRm6KLf3(t1k`UN(g9CCb>P(~?Thga)=T(O z!t<<|J-Ci+xb?(V?gJB_hQ=?MX_#XBI{9fu?OPhx*Y3OY6scB(aaH)4hGdOIuHgN} zm}VZs@u}Mgj-?%Q^b^kvs9t!7r<>gp{hcRf;ZyD~0Z1_93=;ycRzkb~u@%1U@VL7% z+Ww1@dw1KKs^?@Q2&YV0gW!-IX#IRs1IW(`LZE>XbbKZWmynPdqH0>!{u&hj4mz#l z4Nx#Pg>M7T-kvBKQ=bVzV|@7tQVfF!)L0@@7$AodL<1VagVW7bEXw4xaAQ}xbH8Rh z>&3}{N#EU4lb#Jp9m5&jz9~n)TH9fv8_EK1>27Vl8$^nw6xPZpWbqnzAPtW~sV zFz-v%88a}8u+p$JxoI++B)c5o*nnt&hYRl1Nx5a&+d%iFuBZki${BzfY|dwJ2f@q< z2JqVCdZ0%2wq7$LnhAPV($85bfLD;dvWhNLGiqUui#=$?xDDKdl6b!s(F(#97(nvbRK! zf!TV5JNa34;xY-?q8$4k-XbVk-wWDcZ|IQ_*8XmYN!pJ**XSnSb7VIZfAwtYE7{%bbH9R|A{Bd63D75e-qg-|T0oJ#5Z6b{hAIkE8mS z`;rxWW{vh%+IGZ;*d?L$*}nWxi|biD*EPIv&LC>keL?fH6%~&1=})$LXtPX(=|$~C zNgBIbMSj&TuRImsRYoXKBA4OJ{!mPYlH(DZJhgMzGe&(_9BPDbpRFxogOk-UC_yx5nr0e=Hdr64OdFz7Y^%`s|#cn1G& zqt(2#5|pk5Zb>;6^5);Od~@T@aan~YWSxGd>iKv`OO15Uw6KgSPKYrg`)TFkU7-{Q z3t94^d#5wpTSPB(G#Y3voZY{%!sIr(Xs%PV!7fo-2jH^0+M^F7_6F@S98xX>=hs8( zkPxn99Yw2|ee(|9>a1g@3ewpG}k{yfMijSK80YqtVf4)J$J9 zsKf9ENbi@D^>9N}53D5_&h=8ba=7kJLgD*Zx6G=1mj;$=Vj69DC>u}<>~(JWnkUb^ z=w6E)KiV3}!%Ut1M9I3vFVC?Z#Y&JFBuLCS!bYaRT>YdcU`^xkoE56L;|WA%*m9`Rx(qF>{JZx8;QJUW&iy2_jC z7-y4Ur#5rc%PBw{^qaGd>bUO9;WHnX1sg_pZfu)nWUJFuKE_bTT|O}toAguNccu(N zIkA|@f#c2Mm{odQ9N_8hDsbuIS%H{WPp_Ph-ZK$4iB8g1Ps)nw}#qK!9G5n&4&wtg)!?XB$M zNeZ9_eR13o*a7xZ01L~}K@YZetnFaaPU=nK+Y%pjf(V2O|8ZWJ&a5t|NR-<+>0+e` zw=EYa_#dk4E-qdbu~oTX_r_LV&+xd9YiJw6gw^)IKmP~Pv7eHlwV{4+89wXS|EX0Z zy(Cts(=ZoA|K$0IwsBbuGL);YAUi7*7*{2XrbfeKKF%Z-$)q_g!{mkUYG*?~gIsgM z)Bm-qE>cXNH1p)ooRj}wHr3JXqyi4{>D;psGQ4ASu^6CLsU6gt<-p7(>elG!(fC+z zh6Ym`Y#UMCjN zL9M;7VUNE2abPu*F&G&DV^MK~)PxBtlX8I~^qc(E)FS`p{)Zpmf$ke5O_cqm`vgH{ z5)!nv{L8llgq0 z8V3C8G!S&?1u-Gyt8efpDD~ESOek?er#m-P$T z)b*CUsi{bj=M8BRyfZb0aJ${saNIw=)G8G;BI@bU(fVzV-v}b~IysB~B z|54ChVo^A%d6z3(;B(>Tm%8Ms(~l#U>$I`^(`nxG+wGP(t2d|%eIhhb*KM9``hTuI z8z&c=_ge8(l48c*W5p#N&1_n_qHtgF%jbKvFRCNN`Y8+9O`j9H1it$#phAYDRNj4i zCgUVPyL3COrLPJxGZ<#nk#I}2XZQwNXSc%Y+1PY2sM_(-752R8p}iv;#don3@KBko;MmzX3_cnR5OSme5{2s?U8B-PPIs05Z zG>>KWhjhDmo}TJyZ=#2tQ68qm_eS))>Ic+{nk^<-#vjVMMv%_aZ7^{Y*u3KxqBMSU zUp;oAN$-s&Ps~Bqdij}euX(wr?wxdd;x_P6s$DN+f+64>oNdW#P%dLV#Z`h{1eX}i zc!&9sE?o565SN-^-;RZ2yWeO3QTgx^u1=Zj)1h$clydL3PicjY8)v+~2AtrIQg(bB z^W24s%>UrXQk!e8pW@AA@pK={7tdeh8yZPa&l4}kOrG@Df-bW_iBBAJO1v;+T}|+_ z0HzjLkgr(fV&ya;r(=VclwW~zTUxEeQCk%-Y>HwZc$S$ZVZd~ZW7ycA+!uBqU(Wq_ z5kjX3-v&vQgbX*}T~@>f(cYcCD2tCQDPWJzzsPt<@78r2v~^EJ8ydH zwbDjr@?-U4ZF+xRSsUnI?YWlliEW;Hb^)3DP{Mn#8O>!Dq-q(7f;ereUiG_ajwxxw$tx%R0_Y+2lj z7n72Qv=KLgwS*;f`qMlTM$qncDK5FFE&uF?!E?Ic=*Y!7zph|c=oGZG?)s)p#9(NO+h6s7-L?rceLL+W@%5JtmwL#2$rr0C4O zO~I@;@5J2_>|Qn)M?I^sEtf)Sh7k&LD)TO5Q5q#rT1foeS`eaTx9Z+WH;U@zG zGqCD}SYO+^sld?schis9799s)CG#rudw%$FtGZn@H9zdTqAmptk#$BB*vbx9({v{j zdc=CM$XCQO-eJZ#y(ULRQ_Jdoo!QbG#k?)IpWw;Kj`W~pt8QC;Q{;ACfSD1y7NC@? zVLLAQ5d4z+gQS9=#dtP5JR{o8ub*dD8spleabh)Bo>$RFwi$&_H|Lazyc z_7Nnd5!wWrzawbWR;Jd~Vd}&tc0cc!aqqf;fB-#xN3qaD8DL&A(e3 zeJ4u`pN9%PNJ)_nc-WGpdlka0=z%RjRXWVn`H@%FUG zfbc#ABF#qz!4z9d7jNC7dZ-6U~W zYK*`edmU%;`JQ!6$CIz|1P6!Yl5ah^^%?P7r*@hZDRn=ju0O68yB4Z`>9j6c*Ns8o zah16S4X(#1qvB|BMYLxvKt_TJm7gTL&mES(&x>;3%>8sQmI1ADSYY6YbuhM(977cR zMK+zIKsUhwwnP+ci3S{e=XRJOSaQ<3Ad{cbamIZH$RMdWZRT(BHMHB$BfkwU_aTZT zkt5`d=BN+$c_X9CR-R*Dj@@gl8f!k1mDV@-b_>iG;fy9|VTZQ*0SM|HWYuw{FdkpG zeC{_O?I7_&s{n+MSbwz^c^ZMI#YvIW?5x8~4X*`65wb<9`30I4Se~Hfm;W!aqW^?h za=#DXpy@tzE7J;o;~m69Ny^n1jE~5Ru&o9Sp(?+?5^E0|jef%^#UlxRs((NfNia*l zVGu|$YtrNh8ax=bR)9O&g8@r3U+H+?nWw*bAU3{VfSBpKyuL-7Pj>kVFKh;c_&7@Q|@(u&(RVSj@BtE4H#q_=}epn$Ys=!88KS-0T zO29WZX+59sLk`PNDe3OsQBCOL$0^oMwK~tu?WiLX zw4WYPdQTG3H-pa4^~KF69*v?el%g*J+0N5^xVqv3c%x^o`O@Nz z2i+F$_=&(t2+Ow|N2Re33>gW(F!Ko_iXhrq}hvEn?^41 z-?JC<7{KgB!2LXO3t;vl$j*V`i{^<@XK_zh&YO0bPL}26=Q*TQ7 zGF5a{wgLG%af2E!-`qqLShFFb9{^XTgT}ymsnxlFGp1M)&Agt{Y|7(N8KLy`e6&w6 zwRk(8FOx#_Y($dT^y?y5NBX))?o;g>uZW%)-g@npK+*3~5Snpwv+<1# zTsd`orenK~4}Q1R{dUO$GSR3&H`s(B1B@;g>{5IM0=J|QMt=q>{=fY9Nc~hI5J#CH zpbaD68?4eu`@$h%b#~fsND_2c-m)A=eYQ@QsE`PS1lW!gd0jT`Y!rgQH71u*Gkpfd(%VTjke<1c2PZ{ct`J1r#B_P!I^ zAgIk@ajoPP`a|e?kDfS7=&X|smn@PSA6JF59XOWFpq6g;qs2i8O=pF=&{MRYp!5W9 zfb%lMM<8LhChQ+4yIGh=1YcYIraL9pI)SGPS zxQvxXPZ~kjHOEG040q=&A$Y&Fe#kW3fs4q;l(hwNzZt%_Xs$@KwoNA8T0*he4;YO* za0aBGJAP|>Bb?oHi(wHmEKRc`R2+Jw^#TlAA~>B-@Lz_mw~_imUOgt9vWa?Jv}zw5 zZAm}rJ{52$Yi)(FwSNPsI#i6`!fGwBAwc2*xD*!f*{vzxHbPiA?cN?(Xpr!PeOv-l z8F1o%kyX0D)k}1X_5?s}+dd-Tp6RtBa`L{jsn3Q-y(*q%dAHnZqrV%KX%Yz#LMu6h zF_7(V@DRxTV4}Aw(0#Pn0-PFu)uXtBOxoRPrUUGyc6$3AE|Wce244P_Bi6YpC(lsr zyd}1~=-xP+^^Q6f6en{rcAt)Gg-#u`=XS^0-Un zCiOC7&J`@fH;)4@FQFy8n=|SIWivDZ09JJqE>N`|0V;EB{|qQ10qY#5OOd4c#wnz9 zDF`-Cu~+}grvs(PU|vxyJt#5(`O?EV$6#!My8$ugSLyMuiA5kE0Z#bh__?8@>{qo8 zng%*+nE0#L1k5%b_eaDufRM->B9dot+AI8|(`VJR&3uXv#1p!`{%qe_BJRF1<_3;V zyIM&YhNCV8c3Nuj{8NjFdmrNs`SojSZJy9S@+o1OuA8`sMSptnjg!45%cS(>w*Ai8 zI=zc2omX3Z=|;=_!3K|2)(ob~q9a_n{LSq!xZ?iuzM7aK!JO-*Z)3&JFpVkQ*lFe^ovgkv11DWLGs(F;a!e+R*5&80 z&=!BbV@~Kb+4JlPRR&`TekNV4%0>1thC1Z{(WY>M#VJg)aEXX;=5@r`Cy%kp3&=pZ z0bfvDUY-b#A15%O{LsfHY>cb=i>Lb*Vh7fz+ZEzZI(PaMv7yi5p9S_YrqV4Z=EcwX zL_DCPQhu_)*ko#o7=PTaRJ4R0$uBdb4NOT8evCBFunSr03* zz>79BelSZetxmOoC6y+bew}q@QCP?|zR`2LXE$@1KetVi)mHHtX?Djs9{Q?m`eyKV z&a0!l*&JI3)Cw* zgH;w(>i4n^D8OJl#xTHX@(s&+#NgYDq{%#4EnLIU2f1C%QN0J_0(u85903rFj;dT5mhu)PYCs+Sq9_ONMi?plkbepOlg?f$!d60BDiV+;o`_on}S99 zVt-QmU%8_do#wH&W?6Mxu4u%mjVX%r|gf^V|`AZhIwUZBIOn^`XInuCBF_We3qk;kh%n@O<;ofl~=S}2p@9H%W+4?VWtAL_9 zbjywfH{=(xZ{-;x&B=B|Deu=YfuPMG7lhXKW+tU^t2>k z$OIPD1Ys_N?F0Y%O@}u=QXs}k^}|mO2X(s8?KQJ3Sc$G+vuluC?!ti={D5k(ioaoD zpe{;3gyOa5Chb;NpWmPwtSHBOXkSfChR8-%>cE|T--hUHx#UTn%)B=k{dV)m`=qYh z?E2<My4I+GcdwzrY~RjY-w9m8+d(G;lB&Y=S`cKnwWZU z1d~-rsccuQ6nvi|7?cw+ezfPiyKKE{-Q~XY=<7SPaI#05vMp*N#iO}kEFgtIW=(Aw z&6H0EP>%we*Pl6)y|Gqr-ytR;GtBOr8<9^6SKej2G4Ws_(LRHiY3Jw588K^`qJ z{VyDVS^#XJ&()@@l*G{TT*i)Zo;%5S{m3A22zn1P(JxvvAIwPc(KQh{)!@?)yj{8C z-&tf4{7pyi48|?bo4E>@4)-A&`7}- z@86kc5rSONE8ueks!gPzyGJMCgOo&*hvRg@h|I3vNVLCT=V7fNYw%~3?IBRm+-%fq zZ{qyKwCI}(XGVT*14gQw7jHPb_%!V7nHtQP^sNGj0Lx_vLvK?BOeoI2Q7S>dmg1pA zrmio!*$+EU0rB2%+d_NuPskj8AfBRl>TrBd7g7xRdHV7~H&tWp8;e4fq-SY=bUZ@S zfjajTHGFuDT1=tY&~TgZJ8`Q1+&Jw73*q>n*oik8-wx8#cbQbi(A0uorCw~YWzjhd zB>0;UKgaVx?)8SnaY~65-j8THn*cvzkwxV>Zqy7vEi84)Wp#Yw#C$~lC(b*j=Q(Bb z&IKD(k7E+*_Ay;Co)9WK{Zr>#IQlm`&-v)>WwWc|Ili<~*4s2V;;e{m*E8FjQ~eFb zmf|g~zIeL4%87RWaFu;p<0lK{NK_*0qlD^}TRBKEpogGzmfk;_1KDu8g%oc*sKnbqiGfYF$knQeXCxa@J!^_*i(m zBHEPAM;?cdgdo#DKHH6)iXPBd6fDMe5uSD(cmnieEqkq-wx0H~t&0hxI&v;44`a?J zJ`|1X0)&Ze_(OuKb$eJ&L+_qtf3CluW=btf$ne+^0x!wzKeg$`f5#LLs3#J~Di(!~J4u zkywgAy{=#^$h>Fg#_HsD^+xVdvNGF_EPQpJ5&Pcnehbl}1Vw+B+FdPnUdxHRTx-_1 zJ{#Z|frCVDC}__HRPbkSx>vRzvxS<6HSd*~57aAe)qGUvl`iyTW{9`q;@h@o8m4K_eR+WCL`=QzDS<^5cLwLXt}-ibyw#|N>; zM~bFqceYA)8UlH$aHmt;6j$B2TBQ3o8_1cvd~s(S0dzuS*&3x*Z7AUjN>k;$Y8Nw7 zg(f`V?en?Un0aPam#8FuzmANyNP@J2p0o4W8fl_Ra%abADSqH|#_KWvD}6RNwX{bm zDRREGLK5oF0=^mt2WN(sm+7%C)eIDKgnZQHjysn-NFJ10kNLdgZ2@W`ON6Zw^VMqH z%`;Wy@adATubK1p_Q#nMdzCJvZt~yzUN${1SE3v!esv4!l-O|Qw#E;s)#{|EtT?ZE zlwj}RmK>>YK>Z8D_n;!5`LU9`@z**v%oH2+L1&?NaOEuNI*f z*5RK`Z`qgU4-|spqoyr$=+{SRY|xNbbrlr2NFnxiD9(!S+%MNM)y1E%edDU^zKP;* zxl!1kT9zX_z0@$l-->(E^;8PTT3z6M0Zn;Lc~i98bZ|m=p`oVhzz5hVuUL0aC}9qc zpBY+zU8@M2mT9V|Yc-cT7$_M$s_oP4a52%YLEi^cf6V_h7C|OFIoJs*$V^iSLiog7 zZ>}4C!k!j>)v5FM<4;oOkTFqSxmcSFVqMcMEIRV~P!od#2cE8gBQ1&>@RvVe(W_iN z1h=AF77Jf1YV3O5zID>9i&#B7Xz5QoKlh>jegcJqc0E~q^Jf^{mMlWMATFO zGd#qj?`B+~tUZ%WTY(w_$83o^6dMeD(H|2F#68HgI^q0?7hxM*f(pZ%YO9(K0KZf$ ztG@t#snY^4(m1j%_$+m*OqWANeCGT@PtAGI^lE$QE1XU$M7C)f*rdjc40?tT9Pc03 z&-foWM~6TIKEw-F&Ny^MG6FeOL{x4`F{bgUc z0byA#9{x5j{4n0A3}n>cu4xHDc%ktToRqV>V09ghTO-Yl4)I-R?AoQD13A8YP{a}i z0`rIS>PV<`XgYIQB9nJWo-FMBXF1z+x4pqkf8oKj>jzmgebyfn_OzMO4p>gyjN9O2 zA=`GTl3H_O=q`Nn)%U6Rsf))|kI?gTkTD}O^;E_zhIU~spmsc~$9`XKG2SG#($v|08wujvMKrPWzG zPnF|`OWJ3mPFZc9sCyo5J`xu`VR&kEKwq!d*<<1i4wZ$?|FlONR;O(3zvG3FeCIrK z@?EhQIUlrLYR$Sj_nxL$HN*Qy;;%4CMKY!@%`!o?$S2*jS7S1JZ(Z))Jn#Dio-5NL z?hR>?zypEMy~>-no4R&W5K|!)>Q=j& zJ(%uI+n8)Kl@cilIiu<3YR~xEqg3alPok5>=`AZjS^2)(tA_3bC-!K@GbMU6k)QAh!9)hH2r|fz)6d37I|AFZ=ju3loO%CsvJB}c{)s~K4hs;?8L~i8OmM1V7xUukP z>^D}ygrnjZVrg^jEi7)epL*jZ2O_2{3hKG_qZ5+H?_Db6bu8{yIF`zYc8iq2r4}&a6>vsMS_JHH%JY{`#ubEp^lV_RA0rW4Adk#gmyy=Eiet z4CQA4Fzj6B6bOVi|5vn3{CCeRd#+DugkAeE69oyF0poF`R#J;!_DQBisou%EC&2uZ z1<8bcoa>x}&+FXW{i;kS_JADPsOoD$xQ1PV3iqLR76(g%3aGw2=#FGbr5Y3~+_2RZ z9uCZhI%7L6{HpHn`_5lsz$3aB25OOK1G^`bpLVpumN_9yr7+!hI zyQ239N6D`(a)k`C0wxV!go?Jf!0XRJdh+SQ-n{+MEBOf{Fj%sLk>eUhG5SBi(ION) zQq^AD=8ujXq-v%&BG7ZKWIP}G_Dm}?)%AdE@Uyjs zL7O$q*3!Ji&t9thD`n_CyII4)&G@HKuG>h00OEMM?e!>ZJb>gck4`X8()CYKvZSv9 zXc5!K-h#v@AbT(gg8Zy{cw-`U7a@p_NJQiN{jS@urP$21B1YP1vHL;={o=G*PzrS>Q|}B1(@m!Fc$?GkE?>t8~~jao?5&ff!#3g^Qb;%`gpqq6BoU9 zg?(zks}XU=L5T~0KX=);832gXrFERsEIT!N2)@^1j?b+mGMI+%#8D2x5?4m5xV>s#cBle=w3d%XlxoM79YX|$)Xgj%mK(%D&S&CZE8{)xbev8GtX!bDtUEP)Aw zIAfn;#a`2o8W%yjO1>|e=6kv?!gI;*y*5G3Awq{?xBr;KoG-@BG zTlelard*+n?|HM7U2?h9R9zFB-R3nRi*4zcFNx#nC?9_Eg8p672-Q?(HShbt^Zqsf zPzdn~JD--_;F);FXFe%R#Fq@(`j*)FHEK%nrpCIA>Ol@Z4#|D&HoNIroU|ncJc8A- zKR?>lGisoZOS5RM@=irTZA`u$W#(mZ`^E4%-J&-GVYZl!2$Xz})Jk8kM=`s-+cMO; zG8qG#(7;o!ZyW=_2;C@l@63%B;_;6IQp{7a^R`Lcj8o5cZwEcmR1~vv#HqAeoea>^ z?zuhI1h*}2@_W=XROZ8R;tPwy*{v1_!dV<5R9Jx~8}DLymuKL9s*^eMn6&xL^8sTX zZN4rYr}b~Aa+Tw{VukCN@^cXMUQ9;nLh&j*jV)E@zceW7DU!`s)9CnNIt#KFQ%ewe zc3rLkcSQJp#CAuwM9v6j8o%C{C=FCpece&82*<`PKeGSAQ9qa@V8P;5t$#HA5#{dA zyOI2Gf3_lTSOX)9uV2*JA9|2@v9ysV#x@fwpcqsB=xP&DWgz6Zio6ohJ(C znzFQZ%pXW`weyC?gR!Zvnk8;eHeaZnt_(LF)C0jxWvS1=2A;WJ`GlZ9BDp728GAwV zdc;F||MB;#Zmg4QCmb=(=YFUluBP^vQ^mYb9}68uN6(Ne+ATY?dP*jhDNvoJ>`6bt zA&3G-zFiJz+fYVtfF?1k9LPy}&}|LO_6viszLm$)KFMsm2&kdgX~#)n$+RQ+qmYj( zRgKRwf=iA+%$|Pw6pFbIBmgK++v>rGwM0!jYBTHPk7&1*RUA}}23ZbixjcRTj#Jm# z?C#iwFfZSXW762swvQ81G4AR7pO9y8_M~(@$?s{cna6)v$~^+m&*6Lh4a<9B+j)g< zex>a{vL1h1U`Q6PmwVoKr(?5D*q4Dvpz!sL!dLqBReX&1x|29S?pd86&s#C@|aMSQ~KTDd>-aILn%m?V{PvQkXm!@lA-BbuTY z<1n^>(~bzn`eI#gXPf>{n%zzNa%jfgfVP}0RX{?TPOyeWM)|8jRW6Q5o7xV@Ma4Tznpg3^&|WoSGz6rcJtD>UnjDMlpB z>upayUiek3#u3r2?SUOi%sF zcKHDp1+r_>hPmGUz<-BeGCv8XS6Rcr^r|JU4S?*x!n4L^oq)EbvIXmwS-H?;_rW+-+EhIRxdZGt4-rbV^`E| z?cBp~76ezkn2R=8RzBiw8+`LhU5}1w-#?Oc_wgs2_`ZHfn370hEAhm~fpuZS0ke_o z-tkfV0<#bG-Xk;X5w`o|r);t4uuP16Sa(@#D(@-w&>qFl%Ae2AM2ZrmUM*LuEf{^5 zT&W(i&dvPJfymQjL5kq?K&W(;mO&@i9PhSXjH%i@KH6z;?+V%4uAl8d-k_57a+laP;Aot%CY3_3QTS?)^@Z<4~>2P02z4uIA;kx%T>2U)Jp- z(S1z5oQXbu$HymL+Dm;q$$H6(K`5+`-4u$QY15lQpB{5yVidHNs-I0pp8Hbg|B8Kq z^Dna8`~DjEQl=+cj;Ew2!GMV6C9mgZ70zrGv2ENxbi`z31cf^XHm-f&V(YK%lPnZ0 z3~3#HP^oSmn;vfnx3(887+n_58wvQ>uhk?QP8oehnT#m4K;*`QDP4lih+KP4iZsI$ zE-9Q2V_0)C#B%=?Z* z>2UeV7r6%dqcBlF5H4q=y(;(u$J9bghqt*_(I*8zUL2P+Ia@oHWrwwgP#PkyChn}Ko{Vm6`>HUr3VTT1 zr_p+K=Fz=Df92Inw_oyRyk!5#eYx&qO^#je%NJAp9GX%lQkHTW%@J?SKVJT9EjNYe zeCPdXH;`grxF+DK)51X$jQXhmdvRaiUXculJy4=RL3o{-Y%v>|Fiv6|;2Ddi>ZEnE z^1Ng0Al)(~5D}N)cQUdBE~l&`&-u*8?osB1)Hs)0Yc^oyfXFz<5j|(MN#Z{8)R%0j zCAeMJ2Vig6^bjBTi|pyl&d8up~K%2_oW`G~H=j_rEx~wF#^V(>Rcv6^`uD1Em& zVA`bvKcg~ajKaFgYNFeO?!{N@ImN0zSX4UItss-FnQJ%V@p#)X;a+&D(x%#J?Q?nz zKZ+7Z#g7Xz_LgpD>AWDU*aS z*vWC9QqU1HkJ(h)^p7GOqwC(9S+OdoY=j-PnBW;xVl6exzVr3r&@m6$&P$%ikjzuK z)8!(CMT>5hRvifOo2jbfK|ygvlvm}AbMM>akK}jH6B$(RPk&KRo=yXJcWcUp?Q#}H z+3v01vndSvqFHB&d?P|xoOP_dL32003)<$Ndr%K2o`IbP6)blZ3?=7S8}k|-a=QhU z+KzWl*0x>HCH&BK9+=e(>2&|R@wu=@!bDiarmIf#9Uf|g@0eaw z_II{*=6%5(iWy=wabY9-vg5;djLsCrimz>wV+!?@*FJdAGt`D0Zw{Jc3Fx`+woIky zSlo|d^H#B}lkqJHvQ=1p)Z;XAYk!7?VBbx+f_=s~Pep*<eOD0A#*7r>9RVW@;lHHOl&3O^mpV6`reccK|?8suQ7yZsb$-_CNl10eV?$yR*<&mE;X7^f-D7$B%H2DQ zEm?Ec-B0X2s}0iT%A@s$H%z~m`C0mu2e^Fgv=>R@3SFKv_*&vK8@*MOH6qw7y<^4y zJ*QjhgLrXTgi?!Vk`X$3P0z zW?QJac$OQE67)5QvcgGmPaQNx_6b=vPN{NHaNC|YF|gp|Nxg*p{wn?+CyYneZ$Qyj z@_A9r-O)%VVEz2>^w<2ST>HQN^RZ%Qc~xR}`43Q?BRbE;=58j{ix0$5m0>=1ushdb zzftBIpK~=7(0sdSnsz-vdVGDVKK_36eXUdZy>F%BTt!|G28|#^p*0<9em-TjA(7tW z73|0FXqLz`7->2Q2!F9sAA}zF)E3kWPL+3%i>cFj`O!AR7%@>)_;pa9K`JCX zDUg>90vo?4!xZ=Hs1TJ+f1yI&_PX9~vrt6npZ|NB>Jrymr1W73o|+VbcZU#Yt7gBV zNjYrJvJrRByumJrv8*u&g}(Y@!S z5J-|QkO-5z^t8Y-{fUHw7|vlg>FFv&-4HIYipYu$%`Iwk5i$Qt#~)rXj#rd0CQxD$ zXQ0Q19E+WV%@>sxO?Hk8%=u3F8pG(-3FhdtHbj4`>aHh=m+&%q>vt5YZIA5*VzX9Y z(C(c+52y7yRSXT3#{2P#SzmMBNWYhCh?m#`^U=CZSgfdG^x%kSkmt(iEmQX{0UwQQ z7Cu>re9DOOuJ8$=fwGv36D)NCU*leuoXH!wx%&cw8UNgtC+D?7uu%*}Os@rwbX){x zvO!t=>xyWy`xg~+W=3Pn5~>}?$4ap~ZE?VOY5L*taOle&>nb}=zBuRwlaEy7rG_i8 zb9I8R9dUM*BgvjDyc#-n1}XeqF|{8)EenPnr1hsvcPtUNbMSk|l+7S#30(HM{&rYY zEl1Pmk%4^XObUZ?7U?I-J3n7vOgELkv6FqHQ%B^H5Ax(ewt{kzosk`-YQIR)u{W+D zPX8^oaCc#X3TeDvQx8fm-FVW$Bsyj%MJsmJ~KA(*Z=Xc-$(urj}iaR`yD?x<>i=c zLrjg_V3j4RO6*FXq$e3dE;(dCw%XI%mwjCf&+2_p4K~Vv85; zjaY}g;OSyW6RSqAhah)Z*-6;fliyA#YL01^xMED3SKwiS`BDQfrLZVlvNnF5G`Hm| zop7xw^z>WFZuqQO4HprWLJ(Xi|FH4SJ-L8$F@oKJQPSApyYU^`#`om_Q4w#`!ldnv zTpZZxedlDxEkp&=r9y(tXy~h+43Yc*Hx&7vP; z@N_*>H(W2W@dU)LjpZ(l4a;n5qJDQ-z4?6SjA3ak#_`hiiq73{y7G}Y_kDf) z1!PDG8Y>2(8EOalMPi$Hs|BSUM=-3YrFlvc73g-)Dw_M(6^E}twenze7T-AEwCy2uBv}n)hv0AMZ*g3Uy zNBi*V;75Xhgf*3RNKVZ#UVJ;E=dP~Z4=-gIy3R8}dHh54%`5^BszL>u_!n96?QsT& zM_Qk&4WDI<$kAlc9lRO1rTP{oM!i1S3k`AKeUp%9==$h2Rnv80dIQ5-hNM`R`9EMX zHMLdAcn;_~fOvWQjum6YBjv9VfB_jn_{%3yV0Z_9 z=;AG~?nm43hO!O@>3QRbz#QaJX!%LSIx#*X1uYgR-O$%jm7x$&7)J@HPW2lRY4l;E z&$O#}U!QJAL39_mP}@?gs1vvgIImzQsn+uSOLc0l+)4*kcjcyRbH#17^iAWd4$%{X zMbIlzpy;i_A@B9S_`gK{1xSp9tbw#W<=-4%U)X^H4iG`-MnRjjbiBGHzGHX9XAC zAv>PSi0Ds$k<}e6q!D|UxRb5eZ)JNaInAybx;4UM{5S8Ub6P(S0D;($fOZU&*^ZN8 z|1$1$!SS#WZ676lxZ#&s6n2m;nL7So+RIL;UFDL#ULw&&asz6yv0q|a++bw8(s*S%X{((33saX9hflkJbI{_bUakgqX$s8%Qgk*U(sRTsLw3~(@2`3SRSVQ2!B0xpsdDzW|bNAE48Y{vx2rr85IeE^0rAOAX zY-YY0-bFQm4=e^PT~GJCh)2+%*a0}&G_Yx}0}4rS9yxf0AV1q7{06>jjwJ02fPxi~0XPRULz9%-W;2&%#qo5>z4BvOu8C zx{bg`{yGs-9)Li&sR^z^@a9lz_@ZDQe2R|ra`49QBp5bjO9@c!ISO)iuM`Vc{o#=} zOowbR@J93=jXexc1@0+I5ZVZV|6~FUnc&tqddi9bL@W;6Q4enhfB``Hk!UV_>JsUb zXq&-e!+$dN{6&UkK;t71m+M6~!#0E*v4`}&$}!-356=cd2b_&0J{P?eKWs-3G*B!I|^N!#C+;Q^nCqe#6G^AS|?mGu2I=~UEzBw8Yn<$Cc;5d3fUrONN z7JomSv`q*xuuV|BIh=-;(Bkp;$E1KqQ~&;$%iCQaaBIxS_n@}R{*WI3raD95`1FyA zdzAyg@*J+&E5%aMf)+Ca76=FdA7u&{>3G?1`UmTTYy@u)L;;?H#6CyXatZluL*QiQ zZK-Wq5;KwZ7L7ec;%2}A{zA|nfB#HAs=cd+_@Jg#zI_Hy+Q+A$hv#r-NGz*8Z3~|C z>l=P^tSR8v!zKUwtNEeyq%E)@G1=jIK}f5>-*Wh_+S9Ou<6srYe~BSD4RlcutRA2o z9DOi}RjYE_22hP)^YcmaV#JGh6sX2SdGTxSHV&!b#UC>9_R`pZ5NufU4T(-{uT$niRF-4grPv_Fq5PnU=^^@aMDKqx%BUi z1qWc@fH2@_(kHId|NZxeBn@8kUkm)V;K?E_ zJxQSbO>xj^dw*dPv!?x%SruA-6W8Ifee6Hd?Z-{KJs6S>q^oI zuMSFyMl)mZ^nYyIZ>By}TTMh8*54$2wZ07f9KYfEflwf}1ynK&ZvmlcBeY8Xi*dUE z-S3^e^;>fRrT^>G051Y1j0jmE-ra`$VrmGsocL!2Ns5f0)>(9ph?<$H3xErd`tkRH zy@Ecx-4bB)Lp^$U4T;=I%YJwfVsSc+Fu&e--dLrx|VE1vn3nd|% z5wbG}Y$UMWS*N-P-&o-Xd#*&@pndztN>ZC?`v_1rm#R=fTnSV|wL=({SSv04bfC8Y z|3r{H+$gueqL)U7j0t;DI%cQcU5(*JhsccCLS;Acj$ugBtDWecVld`m6%HC=>))6+`ZR5)bqT{pTGC>{_*?c=`l0+ea>~R<$GP{I_F%cRo__IzkdJrxApr27*oL^ zCM4RQ{Mv)H!47U(vXbk5Q07)Cs#t|0 zoa*m>o+GAZiBkGh97n;oB8;Yol;wO~ADrAixM=i3L$hlW$}yo{XQG&_4;6YF;GHh~=4c z#@%&n>4fkA{4sU!?8WSoHece`#C4gk`vmbJfj-Gx3;Ly^tTtCW>o?NWc(Z#>bST|)q5PB@iD6#n@afcvhGY;(c5!-OaEGRLda1C zLB-ReDE)^U@navdLH`KjP^Qk`PaDTpr8ZSK3UUpZdtuR{@=J?(t-cdlR@qTPXA_t_N%%c%J!7AV@ec z?WWx&k>?N$5V$Jp(nw9_Go&*Zu0v8^1KiBOJ`mh2_Lj1H-{HiOl9vn$Z}HnS9%~Cy zlJom-EoQcut^T`>mE{OMOBZZm*YgalZAGq%2-XU}NrGFg@rJ-l4#b-faoDmt(GU-) zCIQ>$tQ|3;?O_NQ(Y40Pd}?ek3NUIw;WV(2&AEp#I{+MR&>8scgAu5FU$*6ci6apNj&?Pg{Xq8bygvEoMtfh_2Dkrm; zA;VjN7vR2lb*>6Y5+gPf=~A%@D@7zpGqK*D-1%-C=krs^^3zYM^xs%PX<0a~ij;aviSQd+;Kp&hE2SDT1<|Ym zep$fD9V{Cg7`PEUZ$a;?AWSO51cjU#fc+|C6s> z7+0P6YGKY5(qiUGCdV$ph_?b_Dl0mH6cTHh3vQ_{xE;Pkuly`-dJ=sIk7*0Y=U>?x zbCsd?9WZ59U21`)mw+A$&4$&3hB$znF@}^@;;=TSyQrj4 zP;p`u%q#fRk@H+#e(-5l0yg$N)?Za$NxuK zE>AvSU4bIZzN!UE^?v|~S)=6>Jj)JX4j(f9WzK(u{vVQ^W=ZC2s@R1jjO70?2NisP zrycQa!%zjR|0^b}KkdxDIy>|~AKXXm>_AvAXRY;L-osS&UzP)#`Ia*~us`o&JUrfm zu^Dp5{IR0iH-}&kP_9K)9#f?vZ-Mt(fxU3hy-PD#a8j%kY{C0A|z=kz-e#wa&OTsi;Fww3hiieU7V$3EWLuiJxGvzq7ZUZtOMO<#{1;Qe^8Kz41S(#iZc zCfyokD;L|ypC5Bfc+IX+>V9U}TE$A?YA|3Pejjt(6tPlzeMK@kB+p>#3bk!*_?W@= zCsoAfhw`gfatG@@y`qfFWDYdho2BOzOWL?^G%_--xyhz>9mCO|PVUl~nSmy%3Hn^O z?X1e@m$wkuYVQ5GtH!A6w+M6+LjCQ7`RbyI$`)rPS7L{Q|HOW@XZ|GaHFZ38Zn$6T ze245ArgL@h*y0KE8@o|uLkJj`IL32#LBS;)H!>XdtgM>dvl0Ua?>i%%?ESPJDlG92 z3?B;TU#luEABc!@2c9@qz76KwqqO5b6*fd#)!mgdx z;GeFAd`GD*=kfI)v~!-oN-m`ZqNQL-?q-}#{J(;cCNU2NlC+G znQ?az1)(8fQu*YRs+{lks;Ad`EnRTxurBU|d*5jm>}c+&lwf|I%(t5+MlT@+@0jL* z8us^+qd9e#6GNpQo;olh8xPYVPGuQVWz>$eJ!|T_8noHB-hmbTWS}+lX_UM7rJT=F z?}INSwp5Duz%?nGwy`pxlJr7D?tqte?1l~bx0#i0a0kV!s^yKs7smJFcQ&a1^N*RQ zyL`Is$+L&$PX@a0$|-~d-MZ6xupt_>pnt&?!V2TB?i?fEt_{G9OXpkLU`H+Ff`r%f z1YG2i!0Y}J;Q5bxbCL%RWHqI|?5`gV6s0G0!`^0HXT~yNMVrfnm!^Ne++4n_ZtrvB z?c~ekI}~T~jOr@F6sAi_HcfdZ6AaNvXO|EKrIcseug#XEIJhZU%<@X0($c*e2R=+D zFSy!#c0+2p!r#~$?_c~!6eN>Q)KL|B)NimQuJpcg2xwPt6TBB`F^1cyN#gX|03Hdi z>@xTzpyo+g;)xdR|LSz$f{n?PuBA;JQflbClEV%|1(B%%kr9cmvy}(&%n?xgCq2x= zIC3q!;yKRDt(|aQ-PcS#a?@w+(?|C{DK)1g-QJLz@~3Y8 z@6t<4HzbQ4-1Ow85_VYRnAnN9c(G7zxLG7wOyKT`c(D^#UbHH?ly6!wH`0G#WoR|5 zTCEK?+_)j>?NTGg~)CuBd05?PRWzLJ*Az9 z59b;?(bShYxciguGwmG`%A8bvHd$Pq(qb5gPc57xta78$WonOp|E%gPb13HnH*=6g zlnz+agzp4QGFA(?cEI#;V(5xh2aMgjJa77UmU46wJfu`y<=);hReX4VyP)(%2Lg8s zIfByn8PWm8A}lJ=!r)!4CkQYpplQqy_+yxcoK6?9&{uG~INKC34j zK;q~iAMNs|Uy)`Ov&$y8NUy%JL1zzZsOMm1g`N+upE7Ajt-<|8>5X!sj6pIZIk8Zv z=N$azj<(>qp?PDl%!U2fIr}3yBhRy|Y*Oy9mijEjqKD5k?l*&5R}g+#^g}+zB$#Ud z5{QJ8w|iiId>cP>jhc$AhCPA+u5#dPf8XEZ6Odv-51F~kW~^27H2Q6@zl58xZ-YS_J^=Q@=@V8ch)-E#c>F)AEe$yQq>2gAI;AkrXp;85}M@_-Zk zVw789ffd`Rfvt%uU9m9SY-+io)%1vksF|k5`-2Nix6D%z55`3YD6LyyF6x?y^#XGe8l@FckQv*ggyN1}s z35<110(A}*=7w>0tk?LUv+mB3nfH3G7bOlPJj@EzDj1llEzrY13Xs>e?_LXetPW$w zTZEBay}*}5c*FP^ytK8Elky<;?dF8gQo(h-q7RmZAGfo4GZ|koHY2AGYnIQ?BN#yI zJm9SCaYShQSrPb&Z#bTGEThxksQHwOt=%A&5c_CFr}D0!K)pXL9t@Iv7+{Hge2mTL z6U=GOZP#MNp2VdyS|x8*GMu^L52!p}Q0gS9)+~Yq+!=L_?K*)0@%3`?F?B1N767f8 z3B@Z=$#9omlfTa}1Q`m~D$$~|kbYq|+kC{o>f^>O!Lg^n8P})`9X~`=2PXv=-5r*` zhV96(l(O4xvTO|i^bIZbrChDzhDrNi4?pP_*Y9rF_T`GKNM68TkT%yqxT3gox*N({ z`hau#B_Qu(G3)I=5ahuj#jVotdS2Tv*h4JCu|*1aEFxF=+kFP9vcSLb?uwzYm+m)u zj;%dla7@H)!oLUxTUGuPRK6Y0UY&Awprj4wf9-s=ov_$p*==_%3^nG%O8z1f*Zpgg zM8FW;M5ew=LPdzanN(l#%hMyf(O0E-Gvd$KE-jIZ&85Et7A-Mc?~>HaUc)>p8C+Ie z(Kci1IHUHpaP`V|Ls2=o%OR+D7xJzd;@V{`j#cH;-DbzH8YH<)_@Jb|P22i)_rj%`(l5?yNf1E_gnA z!|OVa6ffIk@o`&T64wukk69xj;N7Lh^hE+}7&eiGzFV^0x;sXKKFgDTA*v@r5 zIuIv&-p0A`1QtK+`?)Dv!KeE}L9D${AHUk*FcRA|>4ycExiC$;_tM zhQUj|-!%KkEUE}yI*z6DG)F$}&RKJOg?sPF-l`FI(YmR*-UT6U@4xkKn^ zosfeyq&@$V;JV@qauN2DBS_aS=q6yfQVYAred=&Kr$sAU`N&_!87;6u&0DzN^ zY0zKhn%&xAv6KkQD^O?Frv1wKeLu6!THY-(Jy5>->BVM`xnf=i=jka4uP$EC2#V+$ z+IE(^+sotF19K(Z@iY0F(JBuKQK-O~tJ&x|3d=@`b3mqeX)X0lF`hk-eBb2f(>`x$ zUFRjQ#-ik`Us1gxJj~7Res;Z((0wbzp;YgjUuNt_uIkZ%4fIYPEYoLZKfR!p4*vM* z{?NLsMk;++@dt6PJ0-Ofe`o>{7pn(WmViCILj;j|@7XpUncQQH{C6o| z(+2%3@4KJJ#Ve~Wd{-HC?ezouM-57E&$~wd9eo}3e$(~Tsi#9w)ttL;B#gjz%L}nj zT!d#3d@rLVah+@}7cE#GO+$6Se59Li6ALLscDwQNN!`hyWP=wHEyBU!;kMGeM zlf*2H{g(wd;+-%45|B7sj~0&NCq)TIE|FspXYg4P7pQ1qAJkBIRj&E1Jixe;1e56A z9Crc}lxU~j^w?Eo+-TA>3!4)Sy)WK|d_2(9dMtqTd`?JoH z@csqQ2Jz!d-hsWUbDz~ddmG06z278#GA}CPGl8HVXhO3zMv)znhr;1sm-w8~WK<785<7o;1Y5{jmqnTy z@2s+k5#-$XCD2ajRcQ*6K&mnnf1j4(z)hWwLU2pDZYlH05RE+j9M9bQhO-H0nv zRcuYkOqS4+n0m#?#+&=I`~_zYp4YnA*Z6{wT2Set>k-)HKDP11^0u~bcZRX8y1?<8dO;$+xVk1*M@s%5kwa4Ih_sRx{QPBSf6CCTV35`o~c-G#?cz*h0tq_6=z z$94G0Z|XeRSVlF&rnz&?YnDbgZW`ELJ3xS=P2vj<1&JDZ4u4$UDl>y17>7+|mm$FRk645u;qJ`c(*G47!t{6M) z^(^V2ln{wW109BWLY-Fw&Lbpl=9d_Hjfbb>Q=KWC@!eB=kam#6mNZM9gnOkZiy ziSDH{7X~iw=sng|VL}eI30+X!)gT9Ve%1~>f#FoGzpwe^@wR4`S77aAY6{`4{@p>7 zG3TdfHEG=T41TD!2h50^{l2@{m`6f-a|Sx6#=z{Jd=0#yl>DtMvud9Oc#%!6?Y%GB zEv<5llx}#eO*?U`M(zs=E1n-^8jztv9F#o$C_Y6Q5d>#{`QU7Hd5nCU)A0FXLkY6b zuBL|4>r{^)8prXLS_itg;Kw(+lBQ-v&`>2Ab*HhtO0LS)qS#fBCNRfY`ruOifPwYv zb}N&Nt)#uXQY>HF&U7*##X3m|RyRh)R&k)ZQTl(R$fWa2z$i5pk3LyH0Aglb!GJ(!RuUcIeB* zbq$FOHCp%+YeR>WS10L0sh1rfgxpAE-SZ8n3|z;tSK4H=lDoq~0&vfsKOz%yCDfMR z{U;>hhy0Zb3v{Gb>bAa^?udSSr?8_~pEb|l%}TotbRZd@D{>{w>~r!jfwLorFXB(> zS3W&)=e3MTk4-Rl_w!a)sWa2&K9|s=JKJt8`k)!$h~7mmpFXK+4)kf`2FVI9OcdX&6@kYjw-GpN!^^nw~UV0 zRd)L&qJwK}4X?ldxaF#Ze7fNJ!spSsve&7bbEb)01xH!jgbZ+cNi4o8Eswe-Vc_~! z|3@j~1$&}Tsa~dQehpYQ-{0o_hEndyx|cf)w}Zy+Hz-%#ymwkZKXJ6RIsNsUn=4vc z<J*RE;G><>5TUAnXH1vy^mJJ(fvWkbwVQXp;Wsdru4aL=beguWaK(%-M63_-@6 zy@~n}T?<-6g4`7OBQmK;unqVdU_?C?qR=B4jM#jVm4gS;z(mO{lu1p~Glps{kIeR` zCbjpYvY>ZR9ETU829F*izY*HYx=3psW!P$cuQ>>C=!LP&wM35Fx(y}+ZSeE zy1nhu65$lwuI=3s4-a?$*mAoQcD^0K=cYv>q11giW;qf4YJzvgOZpVl!+IjD5NEW1 z9&8lJh*Aj1MO@V-aWg*f!)JtXcm%%?YrF5mE4R0GZCM|^YSOPRj(U7(S~1b(&BOk0 zi-$)U4`!SzND^Gn6js}j7xj7hp-oE)Ok%1cM-KW*!kJIMDV2ryuNUO^AEX8EO$zS! zBj42j$K)k<57lwAq#bkDLOs9ai$_(hV&1MS3({q%M|gAxm)T{-*Y4u<7#q&BUtKL= zqi1U5i{ERUbZ2iBhw#1*3i~)4CTh*6)yds9=r@ml@R9CA%p-{U-dVFI;qsxY-OeYj zjINe;BKbGcYuo7f19JJ-NbGg5MMC~Ah#a8|HCFd4cRx?iy`PepmiJZhw!7-iQ0MCo=f=X!KsVh|(9T9sGq6S7Hfh2NcR6eQDZx7?LEn7U9Wxkg_o zl6$%a-wC0_o}$2rTVgBA1N`W!XIa%r9LZ|bz<-L+>Nt3rAmSq8q5GnsO@2-Cg%oaL z!_mI%Wqv7_eLwUYaNTdRN`~N4$mOT5tZx%=ZVU!CClePPs zUaJP(>%r{$6(ucc7mD@WIBQCl6fiHmk|Q&vNo+xzN~7WmdKx$3Q9SQTCpJgk_;e~S zhw-9csiC&UDqVYVJKds^7y#gWTnFK;&I_{-S_<5m*a^-qmV!o#iK>T?4syLgqqVbt z2^8^Tv1P@Dtg*@uMee+Q{Nx2{Rbc<-$MpF!{mDfO`kn=S>m0XHqYQn5O|e57g!Mt+ z+POyoUdc+>$;7OI#7m0Z`g*J$m`z65vJJr+)dJ_ybx@P<;gkH>3(h++N>Q_AIg=1c z?X+VHcKL8`7l{mLqf!0^Zw^yJR#LQVz-`>}pz`4Kx^>jy27Iq1PqQ~d1F%JsOx7`T)u#J{>!WJVmvKiAHd<`=w-_<+FH-+Ms~ zdb(QZR3-Y+hH@G=^A{F(0YcPBrK1h_3E1E`n_Phm_I0F;2o**XkHfFRSpJ$ow-^n~ z{1~vCes;)~A)ETFAj*4*+2xOR$jg)iC2OODSBRMJorRGZq!xLpJ(j86DdQ1NEeR|`bHnBt} z`H?D>_Gz*`?@1e~CLP?w7WwJ^sZcVdT%=M>hPyr0E$*#xTR>I$)T_sEs+o4jJYXWR zyU2_gp;NpPpErqbijc9q!@ON^y9f7|jZcM)daF`3x?5|i7l9lMK`uaWUhyW^H`{n$ zE71t8sn)d%g_0hhF;eMSDRzRCTj#N5^nCN_4dptn$;Y42j^BI2|L&-&(YUqhAB$)t^rv_$G;7rW#rk9_5Y;`zPYZiNQ3k!b4ZV$Zb?`-iwcYgo9{BRT**`UGLT-|9#gh_&_ z1Cd`b-CPuqz6{S^Vk5)ZOJco=+l@Ykn5h4wlJpC7EfzjPR^y`y2!o=Q*gWMn^g z9n}H$uai#$!5AhJO_J@tJghYB96c9`Nb`>zp^vf;%)SbF_!H ze+D->AK|TVy=~t^pgPe$Ktby`K6f6=EQNZ0lSp|_eNi^d!H$qGuv)r#gb#^J@*1{C z)~$(ekPDBfkQUp}8;LuISEi4(jG<=YVLbnKq<=w?74sgR;W3O1E8)TxZ&}{wTCrHNN^sWT=9z zw~SKqmkeBB^N^BCByP3t0)O9YI1Y_clI_~LG60w9cF@+9-LC0ybel=?;+9K#Zx5dC z=16yr2vvS)gZsaOp<255INqP##=P#y%9RLi8WiCzD>faooYqs_csC?l7(`KS{1l<~ zLJ}&AUG(IkI~x=t4JI8L28H?h)0OKZEu$~E?yTPH9NCn7e*f9f6lK@QO_UIwTeTAs z73w$^c{hucF~Bx@=i}-uwaapKvp`D4n@ZV2>Qa4WU)aB2jev?1>DivqefZT=#8W_% zp_*TZT+4N*s@xr=P~&HWT1ExiXoeNpY0s9iGCS%GuRu4Ci zW)6t7TnBRT-6HH63~#qYX718`E2qdz{v|*h6Go^ySUT)P(F8MjJ3pj;>VyBP^1fdy zl@9md-3i{^?+G@d7qB0lqKx~0;iXk_5BbCNFU=I0)UbnF(z$-D1Re+O6S&WTY-81j zB!rqpf#lpp_3lIoGgGsDgL*JWh50w3d-pGaea8R`6W>&~ni0d}`l#k$XuI6{;Ua;t zsqYFf4?l=(eeT1I>FYKm@q(>D5^ly@@Hea1E_n37CH1M7Oy39ZPDVs&DVp$xo9xE! zv}Y`crDf}RdbhE%vLkMk-Ff&|WfD&~AfCR{xko#!lD7qxx(xL$n~%tzr+*WLQZk@- za)#e_)cky44B^`n_xHi%@H3Es>ZCbJz=Voy$Z*Vf@;S*dwf7SJ)ANssi%wPAjjt$s zu=n(>(ux&7_d!bKCHIU5T?D9mA%*n+RlG%uNr(#L+RB)r?=!&PE#CKxB8@z+tOyJP zYw}8cdPb5AHO{cT1i5`weg(&&70>izdUY z6wh1JVH8`D0*8E371Vi-o~}N%Dw{>OEAT?bbQtuu8dt zQI*~`>Z0zeG*$C=JnAUCa!mI^>_0ZtIG7@Y28A2*mXrdx*;FXi1a5d|thF#h%{&Jc z9n@|u_)xTC$ntI6Xt&9z;C{`x)1|K^6W+^%=13Je3C9kK!Dh;vS;7$KB*0FuOFhtk zp1;qCKE6A)MudmQqgPGu;k!v%b+v|?=d_sSAvUPSw=YNoyfJBSQ&E{37)y)BJKLLc z=4qo5ZaeNZ_6MBaA(Fb|w*O)~;gWnV1gvsDuLAU|K;)*fBEN7=Wppl%vj||k|AWCw z){!ZRO5%*1en`tDdakL?+G5UoYSdYBs=?Vb+9DwIPO?GxT> z_NW$qX&BcMaD$-E4e{H?$s86MC)=@3#=aHR3o=bUW zA%j-SyJyU`LjS=}PQ&Qjb(oJis3f}`Y%P_uN%%XCAs`dfC|b!Cfc*}DWE(|C<dXnBV^e`^~>Vn_o?%Cn~HVmDw&7!)~o7gnLqVo+4KCIj;BAV40QMKdgi12Q5D)_T;WjTy;KX=SVEXoa}^qLl|=9M>nhSB%+g2Ia)sARb{}I@#oZ1ylD@W3azU`^iIvs` z-4{C7T=fjr|L2#$g_U4jcZzl77EpF>92rs1KAB%w5c+e`0$HV42m6QPA`4zt2M4Hf zKhnO!QCe_9A@ciFHe})!K?s_CjcZGs4((*0yREG6sY51a%t|M)W^hg&c2C9U1MhZqLv)`$y>M zPQ95eUmhL)`XxZ{rUl`WcChZIc1mb&D7(2F70c`zTdLkp{~k>-TMcIi{H1uOF6lx% zbiRjXDp#DWJ#IGxIft;(VkK6%5Au1)i>ors(b3V{+FA7?w;(s{yyr%!^LN4j;WEub zqq>?&gm%61pW#oB?(I{P&(C?KF(n`Ek`w8k{)ySnGW+sNzv>hx6eMZPDLR+w=0Qsj~s zSle&7YPrlnNXA92TRhuoO?PlLu2f{XsfXqVRqNEcJtwkKmiw+NHj&j}D1k^2gHd{j*QCCj{lc9eMFr*GcMy;>Gm0#F$dMZEV|eRQ$11 z+7Z{dPUrfp>|t8F{pW&kr=y8!f{`^LmTqqC`TBcUBd}A1fN#G7Gdl&cF1hF|cl+Z( z8#O(YnAZM<)gj;1|E1H?$W5?|v^cR?s?NOW8{lWFR#vtXO_X2~^yR4UMMt@!b|=_n zO(w`LrN0D_=?7s^?-FP>s$NCfW=ACU<>bCvvHYlg8Q{m&hu%pKV*O%?Bv{!NO@LiV zB)0Q;Ze8JuViu)#OSZ%9y!~6hO;+9t?H0T6W+*aR`7zxl#QZzG=}r*e!Udzw9(JNB z@8!Hhmy;I}XX3yr1i>mg>7l;+F6e3{3&LhC3nXM+(c59)g5g4>M%OgjG_DgL)8ssY zC$da(Mc9)u*z{;pFEl3A)zO*hNOE@m*@Lun+fF+@J-2<(wSc`f=Goh=scA<#UM^KJ zU$Nbyf03AN`QfAOmG38mw5DC@J|V>Kpo~HJw?WCa2jFN1^`#Fs;ivi}SXNuvB_piF zHJnY-`@1*o7%o6PkNy%Ek%Jg(T|N3C2Lc~Y!hz-iDWkaYt@qPfj^ri@x%*mfe(&{7 zNY71$CurE{ykgMqa7gbJ4-wskBgB2TA09mUEES;j8D5H$&QdA4-&bn4o!tVaN$VP0 zL^c=he?QA{6Y9{CobmV%%k(u}gm`cPt{EIisgvev1{ZMm$>CT-NQnQbv@owFYhI6L ze{lG;9wt%fU zhuFu{f8H`LdPtx_AimJ^dL{R>KOUV2W7ag!+SnORkMDts{`wCC9A9nk8-CS;vdHNO zO_Y9bfc6z!j{xT7a$J-89|V4?P8*O4%>A@D{Ga?i$3zY;luQZ-N29C5B>k)|y${!& z#`FM$4Kc{YM51fL_VM+Wj;-H*G^&n`T&NNj_sgrcIrx$Wy;rqGd)(UY!T|zDeK24|(gaXU%4RKWMrMSk<7w> zPD&LaY0Yks4|Q%hGcvZWeYLT!+tBTruIZ$&jRyiM-^=uq-`RiAU*$=mWy|x<^Z={P zS-W%2*rh0T8hQXt~g@cvlxD{3SmE7IewiTT}S`^rczs}Y2J2&Cr z;(xNPs_oJD*3DncFP#4f5g=_5{T{3&Uo^quBk-4@me23x5kofMy(S2k;PV=qIeQhb z3G<#J*9zrJg-Um9#Sc}e(^K$S8!Hq5{URjAoY5vqUy4f5hpjIxAKfUVU_)jJtk8+OYF-c zM-5*`om?Dfm^zSf#x&k!m;}^5sBrQ$6gx70F1cXohJfFh3;?bvDqjZ;!s-3woP-Pwn)j;wFb_-iiJ(aePFs58hp7#4{Vn-S z7yW*;dzGB`n}E<*gOM@ESi8FH(8715t#o>6&x+_K-D>8eYe$~asWD6Mct}V#hvZD_ zsg$ZkXP(Z=r+5bYeO`DyJceb{L1>k_d`xR312@%zR6Ow962hV8!|**U3x7y7PdVMN zAZ{f2(OHEsFPv^f#@@IF!TrlKLy$=7w4}CCTBSC@soAI-ux;xjx&?7_fzVzIJTYYe z)jCRkwX%F;MqppriHWk{(a)Jd!dix2?5XzkDwL7!$?_}iERr;p*`_ru!Yq!&|5Q2t zO8}|ox}eRq9JhQNYdNXMSY`ObiR8;Ifqf;n?cENV$cHYedgQ;^XwbM@`BODHnwSx^ zU@zzTAnZo6uB5*%CM}bonp>oUgV}p@h|=DG zD5;F9k9e#>uQlPPdH4$ANYtOdqitHknv!{)g)E<-cLV7`mQYrqjPtz1Z2V4f*N%#t zI|gUpiRZW*>S?*-I4A`hV(E|tI`%z4A4hNuv%*b}$A4ppOy})peI|IyI2(>-+5)d9 zu}#;no-i9#&3XCejO5$Q6YK^Z<1zhzHoI4nnephJlnE^woP%Er> z9p56LMT|~Tk9nNKy+AjaOY7~H{>oMFOQCKBTYBNGN+jpQP|UP2_7bg zmfA1}yE3E=e3dlul}NVnOHTETVk&k=rrMM_XV7jp{)YJxZ~iDj-C(!%suzGykd2nY z7kC*!>i;s1yO6+0j%6O7O20(>9)Ry-T|qwYH=nq3*SvdW-Ts5{cq+MoQm|z=_B6lW zWR9oNNM`o(68mxGH|5swOs#n?y2MvY%xCZEtxl^7MSmyjYF?7@vP+_ z1?IOq{%+XcpmcH|k#obuaQ((^gStR_lpRORWq}QU_5evhm-*jvQl=Y+DfG2S#nsFK z+~g`ycs}I;WEko0m-=$*-I|SgKo;UM5wHgzaR{VZ+yOiR1yctFySfP7LTcNg9q0&i z%D*7y_z?)qUDb;B!)Vpu`lt1&;anJ^gKSctTHqUA!DHwTKgLF)6q%#f@jo@dRIoNK z=zr1ATUN`d4quwMcGMfsjWF%=y@IStoB2pMi~I0Lmn0NO>e5pA|F!TyI}g!J1kP}^ee6VQqr4LccdU_C?I zxskHnWiu;=MY84wv~o`R1{>igB<3C*8{vsfHK`i&3i#4LmUAvplp#Ut#?1^o3%X$O zlNG^XXK+uE3y=ah>$DVP!rv3B&KwQzv;iFg=-Kjya2lU&oEtRJjngT^e{aNZcTw+_ zO&LUHRuy-mt+hICm?a``%R_$}lsn-6J!`!n1NtukQujQrKdDbaoz$&9=7v1X!_@m< zV=&|8fiJGHt3+X`gH;dGD=t`q@iTZt_Mg#K%o;V_d2N=M*s<<}9QcotSvB4xLd9f| z9tJTON9>}|YB2qcT4)_~bC+?xdt;p&Wx64c*~uIW;|#J9KHpQ(PWm)&fhy<#;2Phc zc5^6x49VAwMMLY;5lPpj4}J+)Vm)Jg;p%}UMu_n7g)1+M!%wWn7y~kyQ2>Z~j6u|m zqhRz8V2nB=`f?-dpCOX&Bjgb%J&e?xD1~v6S#_8u(8jP*5uHLj^){6B&& zfd6TGy9gk>C=9rSL3n!&#~lhW04{?xBQPB=!Yz+yh*-9gP{Wj!tm|Gehj6Qlt#)}h6~3yT<0@%PHpRK+o8ytKaB82 zA!u7`yx$SigIUB0bkhUlSS}f0*fC}P&2G2$4IyqWcU=0GfcAKgze`8-EwC_3UmG=~06U3d^I}fCGWWTG=b}vrix+Z$b3x%~01l9bjk`4Fs`_L z2O8XY1m5L8Za%^jgwjsPT%Q_z$3t4dODm&HP$5<=PEFBdMNS1CBwbVsEZ|X+5+9Uf zvID^2`20&QW|*_Dirx<}9s-T2^DCBDnnFtF!ai2-#|6mue=vL3URsh@}W z$g*91Wx=SuTQWLdO}(`c0wcXC0yr;@C*UdUDV;?Q$bERtquR{zdIon|J)3WxqNFkc z1VA&NcfMgP{3Q_A3f2}_1RyC9295v&aU?DV8iKK6N{dv)%fH)PoM+CV`0LAa%x^$N z&iqVR>NPWNg>?E?IIn7H(+1b3xG17dvo8=wzAl|?!e9Z3(m!(P1iKMG%IjxEwzIBJ z#UH{)-j(F;^vA?x1E%7y#5WZ_Q+YYb%*HGcenfx?wLwR{kQMfY3j0$suvmwnU54uf z*mNJM&w}aEi6*{lG=G2@dNd6{5kpsEqIM ziofW;0*6-%7~RS>LVgqjwSlI_tpP^(AH|qfQ6a2j<9YMXfPErSxHc(m-ux{7-_qn) zxTfO}OP2jL0rk)wwFsP1J3^lCE%5Athxneo0Lhz#QwDrkK%#`~Acpzlp~oTM^2`MU z+X)v|G0dI?si`TpdNZ(a2G1GX%RwOY(9?>-gF0KmafN(1t}yGHAOI@f2X6ZFm~k1w zl_BDa1qOe`#gE9Y9oxt!p8(ss-21V*J3{Dphz8KcI&e_nsv+!({}={D2MLuKIUw%_ zNe}NP`rObl1y#0b>uhZ`4z!z%AY6^IlL0lY-~SS5^8y}2>^&EA=~gd?insf%CgQGY z-@x}h1$88xlW{h}O^D~u|v7>+ZnP$uQghQYJ(7KSNn0TXyUcrT`!ApqL@00Scm zuOQi{5o0KTks|X?fCylu`VQT5t=-7N_l7eKarxGrssu&aAY6@6r-~j+PN^;>bUi3>gmAifUQTE z>r;Ijtlx4zhdvt=L=~WL^#{=Xm3y_8tl|{pR}Lrxt8CyVqh%pMwGKNu9w~}vl6rpV zPpWiCkH3m=CFwdimL5Mz)!v`K;l1k4>O4PUMBbV}D?5&1!dc>H!EKdV?X1^GxtdR? zRmrsMlR~&u*8feEQTF_tICIl&9Gl`2DUXe=!oGbqiG1TOCV-k3^M20AYLx%Rwi1P z)^Z;?c^EzE|K4E0EZ5&A=HFi-_#E*>udN8$&E0@Kc(adZE6OLu&JYY{Y#_N@VxNs*9j3rwUfF>PU8mei&olM~`<$CVmMh_A31naIMEkAWz6O7UrT|+>C$}w4a;#2~SgNqV%s- z?A-uV6wFbPicx`M8WMgQXAYZ>-rOI-tDUjAi~Ob-nDEsZMS8g*>Lbd5_b4xweT*|_ z-20URa{5(1LaGhg>_g3~EMbrivx7{A9c8C+E#k<1+3X+WByPrc=*uhUFsL9#<>c~s zOa=syLCr4nDkKEgdWfU(OW@?;QKId5<+Sk+<2Y=Let50|n+Di_opkGuD0Y!BRuGz} z@b_hNevq+;?~vvmZsoHgjD>M72snoy586c>*#Si73_=kUJ?Bq^QR1f<{=bDJzVNVd z{mZ%yXnk4>ks}M7Ytl^xo~4h+bCSo&ioh?5Jtj3iB|N@TK-0hvIPR~EDaB{3=>#AM z**i`GRjXz%G@V(Dr>Rr%z;WI_*5gYP>){Ux^!Opt1jLBb zpI}jAPD-ahO4hA<8{qjlg7}ZeLXHnl+w}Ww{zn+W3H}JOU-(=6Ag97M4FxtvGt`5{ zmp}voj6^!o863@=bAWVOefU99?cjGi_F@845P}hl=?d>6X124!M@}}55^X?`lvLS+=m=&r?7rVNGenwPjv)eAOeHVI z=B*y#vn(l9){Y$%%WskYGj?6?>^pouTFz?8dNA>P%*175f8epsp(SiAd|G*b7BDOv>cAwUqHRKL3 zkMnK=mz_To%DMSemz{t19Obl=^E5T3< z3J&rO2EYe$-59|)DPM@z<5V!&)NyJJ24Z|N0C)ez555_K)w)ds-Vyfd=1ubL(|6kjm6)QIAIUK=Y2ZJ;MA9tc|;;(}V z{MN#89L*H^yYycOob_>-zJl-Kd&9gx-tdpC0Oj7(t zF~Q#?0BU0r>X3c)!r$_YEC3E4CxI&@U>=ykEIt7W0uxWnjWM_`=Ckaz!dZDBo#Rku z^pD-nf&j)j8@?Mb{f~lRV;RE$^|#2aFiIn4vHEX!jB{Ww;6FY8_4Bh$V?L2TtT3h) zIJqo8>|uZ-O!xL0h+wYu+E#{e!)8S`rvs zM^v4SXXYfxhn!X_25I2?Fl)py^)Pon<5UxLh(BD+6u>!SD)(E6{|zhnn#6aDb3q6e z&rs$(*l%;2L*DR81(*jj(aiZIO}+wpzYcp>KMoWYY2R#{Fmd$c|@C;+e7;N zU}28#JN&3(HcTXvCyb}L7p$|5<1~EmA$?2 za8~t7W3|c1$c4vt_F5ac2TO!UU3y?I`;>4!PHMB2&+Dw=1E%sk*IX%;>yy`R)zwJ} z7#w(d(|avep9M-g{HebGy9)pR>;KOcSrHS!Y9RdI_z$bAu(M2T&?SvOcC0@rZ}I=H z|5CQ(-dzfMFq!&QKuzp^@)m*IyQd>-=9!s3(A1=j<|8LtiHF8N3`PK420N$aqG5`Po literal 0 HcmV?d00001 diff --git a/logki/logki.py b/logki/logki.py new file mode 100755 index 0000000..82c2eae --- /dev/null +++ b/logki/logki.py @@ -0,0 +1,415 @@ +"""logki is prompt script for going through the logs, for example of perun ktrace """ +from __future__ import annotations + +# Standard Imports +from typing import Optional, TextIO +from dataclasses import dataclass +import io +import sys + +# Third-Party Imports +import tabulate +from prompt_toolkit import Application +from prompt_toolkit.key_binding import KeyPressEvent +from prompt_toolkit.document import Document +from prompt_toolkit.key_binding import KeyBindings +from prompt_toolkit.layout.containers import HSplit, VSplit, Window +from prompt_toolkit.layout.layout import Layout +from prompt_toolkit.layout.controls import FormattedTextControl +from prompt_toolkit.styles import Style +from prompt_toolkit.widgets import TextArea, Frame + + +__VERSION__ = "1.0" +NS_TO_MS = 1000000 + + +class BufferedLog: + """Buffered Log reads file on the fly keeping it open and returning lines on demand. + + :ivar file_path: path to the file + :ivar block_size: size of one read block + :ivar current_position: current position in the log + :ivar end_position: last position in the file + :ivar file: opened file + """ + def __init__(self, file_path: str, block_size: int = 1024): + """Initializes the buffered log + + :param file_path: path to the file + :param block_size: size of the read block + """ + self.file_path: str = file_path + self.block_size: int = block_size + self.current_position: int = 0 + self.end_position: int = 0 + self.file: Optional[TextIO] = None + + def __enter__(self) -> BufferedLog: + """Entering the context + + File is opened, and we infer the start and ending position + """ + self.file = open(self.file_path, "r", encoding="utf-8") + self.file.seek(0, io.SEEK_END) + self.end_position = self.file.tell() + self.file.seek(0) + return self + + def __exit__(self, exc_type: type, exc_val: Exception, exc_tb: BaseException) -> None: + """Closes the file""" + self.file.close() + + def read_next_line(self) -> str: + """Reads the next line in the log + + :return: next line in the buffer + """ + if self.current_position >= self.end_position: + return "" + self.file.seek(self.current_position) + line = self.file.readline() + self.current_position = self.file.tell() + return line.strip() + + def read_previous_line(self) -> str: + """Reads the previous line in log + + :return: previous line in the buffer + """ + block = "" + while self.current_position > 0: + to_read = min(self.block_size, self.current_position) + self.file.seek(self.current_position - to_read) + block += self.file.read(to_read) + self.current_position -= to_read + if "\n" in block: + lines = block.split("\n") + if len(lines) < 3: + continue + last_full_line = lines[-2] + self.current_position += ( + sum(len(line) + 1 for line in lines[:-2]) + len(lines[-2]) + 1 + ) + self.file.seek(self.current_position) + return last_full_line.strip() + return block.strip() + + def get_current_position(self) -> int: + """Returns the current position in the log + """ + return self.file.tell() + + def move_current_position(self, position: int) -> None: + """Moves position in the log + + :param position: new position in the log + """ + self.current_position = position + self.file.seek(position) + + def close(self): + """Closes the buffered log""" + self.file.close() + + +@dataclass +class Event: + """Event represents a single line in the log + + :ivar timestamp: timestamp of the event + :ivar event: type of the event (either call or return) + :ivar tid: thread id + :ivar pid: process id + :ivar uid: uid of the event (function) + """ + timestamp: int + event: str + tid: int + pid: int + uid: str + + @classmethod + def from_line(cls, line: str) -> "Event": + """Parses the event from single line + + :param line: line from the log + :return: parsed event + """ + parts = line.split(":") + ts, evt = parts[0], parts[-1] + middle_parts = parts[2].split(')(') + tid, pid, uid = middle_parts[0], parts[1][1:], middle_parts[1][:-1] + return Event(int(ts), evt, int(tid), int(pid), uid) + + +def singleton_class(cls): + """Helper class for creating singleton objects""" + instances = {} + + def getinstance() -> object: + """Singleton instance""" + if cls not in instances: + instances[cls] = cls() + return instances[cls] + + return getinstance + + +@singleton_class +class State: + """Represents single state of the run + + :ivar current_line: currently highlighted line in the log + :ivar real_line: real number in the log + :ivar buffered_log: instance of buffered log + :ivar last_command: last executed command + :ivar current_timestamp: current timestamp in the log + :ivar first_timestamp: first timestamp in the log + :ivar stack: stack of the calls + """ + def __init__(self): + self.current_line: int = 0 # Tracks the currently highlighted line + self.real_line: int = 0 + self.buffered_log: Optional[BufferedLog] = None + self.last_command = "" + self.current_timestamp = 0 + self.first_timestamp = 0 + self.stack = [] + + self._log_content: list[str] = [] + self._buffer_positions: list[int] = [] + self._buffer_size: int = 25 + self._buffer_log_start: int = 0 + self._buffer_log_end: int = 0 + + def get_content(self) -> list[str]: + """Returns current content of the log""" + return self._log_content + + def init_buffer(self, buffered_log: BufferedLog): + """Initializes the buffer from buffered log. + + :param buffered_log: buffered log + """ + self.buffered_log: BufferedLog = buffered_log + self._buffer_log_start = 0 + for i in range(0, self._buffer_size): + self._log_content.append(self.buffered_log.read_next_line()) + self._buffer_positions.append(self.buffered_log.get_current_position()) + self.first_timestamp = int(self._log_content[0].split(":")[0]) + self.current_timestamp = self.first_timestamp + self._buffer_log_end = self.buffered_log.get_current_position() + + def move_window_forward(self) -> None: + """Moves window forward by one line""" + self.real_line += 1 + if self.current_line <= (self._buffer_size - 6): + self.current_line = min(self.current_line + 1, self._buffer_size) + return + + self._log_content = self._log_content[1:] + self.buffered_log.move_current_position(self._buffer_log_end) + line = self.buffered_log.read_next_line() + self._log_content.append(line) + + self._buffer_log_start = self._buffer_positions[0] + self._buffer_log_end = self.buffered_log.get_current_position() + self._buffer_positions = self._buffer_positions[1:] + [self._buffer_log_end] + + def move_window_backward(self) -> None: + """Moves window back by one line""" + self.real_line = max(self.real_line - 1, 0) + if self.current_line > 5 or self.real_line <= 5: + self.current_line = max(self.current_line - 1, 0) + return + + self._log_content = self._log_content[:-1] + self.buffered_log.move_current_position(self._buffer_log_start) + line = self.buffered_log.read_previous_line() + self._log_content = [line] + self._log_content + + self._buffer_log_start = self.buffered_log.get_current_position() - len(line) + 1 + self._buffer_log_end = self._buffer_positions[-1] + self._buffer_positions = [self._buffer_log_start] + self._buffer_positions[:-1] + + def process_event(self) -> None: + """Processes next event""" + event = Event.from_line(self._log_content[self.current_line]) + self.current_timestamp = int(event.timestamp) + if event.event == "call": + self.stack.append(event.uid) + else: + self.stack.pop() + + def undo_event(self) -> None: + """Undo current event""" + event = Event.from_line(self._log_content[self.current_line]) + self.current_timestamp = int(event.timestamp) + if event.event == "call": + self.stack.pop() + else: + self.stack.append(event.uid) + + +# Custom syntax highlighting +def get_colored_log() -> list[tuple[str, str]]: + """Returns coloured contents""" + current_state: State = State() + styled_lines = [] + for i, line in enumerate(current_state.get_content()): + if i == current_state.current_line: + # Apply a different background for the current line + styled_lines.extend([("class:current_line", line + "\n")]) + else: + styled_lines.extend(get_colored_log_line(line) + [("", "\n")]) + return styled_lines + + +def get_colored_log_line(line: str) -> list[tuple[str, str]]: + """Returns colored line + + :param line: current line + """ + event = Event.from_line(line) + return [ + ("class:timestamp", str(event.timestamp)), + ("class:text", ":("), + ("class:pid", str(event.pid)), + ("class:text", ":"), + ("class:tid", str(event.tid)), + ("class:text", ")("), + ("class:function", event.uid), + ("class:text", "):"), + (f"class:{event.event}", event.event), + ] + + +# Key bindings for the application +bindings = KeyBindings() + + +@bindings.add("c-c") +@bindings.add("c-q") +def _(event: KeyPressEvent) -> None: + """Quit application.""" + event.app.exit() + + +def format_time(time: int) -> str: + """Formats time + + :param time: formatted time + """ + if time < NS_TO_MS: + return f"{time / NS_TO_MS:.2f}ms" + else: + minutes, milliseconds = divmod(int(time / NS_TO_MS), 60) + seconds, milliseconds = divmod(milliseconds, 1000) + return f"{minutes:02d}:{seconds:02d}.{milliseconds:d}" + + +def get_stats() -> str: + """Returns statistics for current state""" + current_state: State = State() + data = [ + ["current event", f"{current_state.real_line}"], + ["current time", f"{format_time(current_state.current_timestamp - current_state.first_timestamp)}"], + ] + return tabulate.tabulate(data, headers=[], tablefmt="presto") + +def get_stack() -> list[tuple[str, str]]: + """Returns formatted stack""" + current_state: State = State() + lines = [] + for f in current_state.stack[::-1]: + lines.extend([("class:function", f), ("", "\n")]) + return lines + + +def create_app(buffered_log: BufferedLog) -> Application: + """Creates apllication for given buffered log + + :param buffered_log: buffered log + """ + current_state: State = State() + current_state.init_buffer(buffered_log) + + def process_command(buff): + current_state: State = State() + cmd = buff.text.strip().lower() + + if cmd == "": + cmd = current_state.last_command + + if cmd == "help": + terminal.text = "Commands: help, next, prev" + elif cmd in ("next", "n", "j"): + current_state.process_event() + current_state.move_window_forward() + elif cmd in ("prev", "p", "k"): + current_state.move_window_backward() + current_state.undo_event() + elif cmd in ("quit", "exit", "q"): + app.exit() + else: + terminal.text = f"Unknown command: {cmd}" + current_state.last_command = cmd + # Refresh log view to reflect changes + log_view.content = FormattedTextControl(get_colored_log) + buff.document = Document() # Clear the terminal input after command execution + return True + + # Define the layout + stack_view = Frame(title="Stack", body=Window(content=FormattedTextControl(get_stack))) + counter_view = Frame(title="Stats", body=Window(content=FormattedTextControl(get_stats))) + log_view = Frame(title="Log", body=Window(content=FormattedTextControl(get_colored_log))) + state_view = Frame( + title="State", + body=HSplit([stack_view, counter_view]), + ) + terminal = TextArea( + prompt="> ", multiline=False, wrap_lines=False, accept_handler=process_command + ) + root_container = HSplit( + [ + VSplit([log_view, state_view]), + terminal, + ] + ) + + # Define styles + style = Style( + [ + ("timestamp", "#ff595e"), + ("tid", "#ff924c"), + ("pid", "#ffca3a"), + ("function", "#8ac926"), + ("call", "#1982c4"), + ("return", "#6a4c93"), + ("current_line", "bg:#0044ff #ffffff"), + ("text", ""), + ] + ) + + # Create the application + app = Application( + layout=Layout(root_container), key_bindings=bindings, style=style, full_screen=True + ) + return app + + +def launch(): + """Launches logki""" + if len(sys.argv) != 2: + print("usage: ./logki.py .log") + sys.exit(1) + elif len(sys.argv) == 1 and sys.argv[1] == '--version': + print(__VERSION__) + with BufferedLog(sys.argv[1]) as buffered_log: + application = create_app(buffered_log) + application.run() + + +if __name__ == "__main__": + launch() diff --git a/pyproject.toml b/pyproject.toml new file mode 100755 index 0000000..eccb5b9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,111 @@ +[build-system] +requires = [ + "setuptools >= 40.6.0", + "wheel", +] +build-backend = "setuptools.build_meta" + +[project] +name = "logki" +description = "logki: Log Analysis Kit" +requires-python = ">=3.9" +readme = "README.md" +license = { file = "LICENSE" } +authors = [ + {name = "Tomas Fiedor", email = "TomasFiedor@gmail.com"}, +] +dependencies = [ + # Build + + # Other + "prompt_toolkit>=3.0.43", + + # Plotting / visualization / output + "tabulate>=0.9", +] +dynamic = ["version"] + +[project.optional-dependencies] +docs = [ + # Sphinx 7.2 dropped support for Python 3.8 + "Sphinx>=7.1", + "sphinx-click>=5.0", +] +lint = [ + "black>=22.1.0", + "pylint>=2.17", +] +test = [ + "pytest>=7.4", + "pytest-cov>=4.1", + "tox>=4.9.0", +] +typing = [ + "mypy>=1.5", + "mypy-extensions>=1.0", + "typing-extensions>=4.7", + "types-tabulate>=0.9", +] + +[project.urls] +Repository = "https://github.com/Perfexionists/logki.git" +Changelog = "https://github.com/Perfexionists/logki/blob/master/CHANGELOG.rst" + +[project.scripts] +logki = "logki.logki:launch" + +# Mypy configuration +# ---------------------- +[tool.mypy] +plugins = [ + "numpy.typing.mypy_plugin" +] +exclude = [ + ".git", + ".mypy_cache", + ".tox", + "build", + "docs", + "logki.egg-info", + "venv", +] +disallow_incomplete_defs = true +disallow_any_generics = true +no_implicit_optional = true +no_implicit_reexport = true +strict_equality = true +warn_redundant_casts = true +warn_unused_ignores = true +ignore_missing_imports = true + +# Pytest configuration +# -------------------- +[tool.pytest.ini_options] +addopts = "-p no:warnings -p no:logging" +norecursedirs = [ + "case-studies", + "venv", + "docs", + "*.egg-info", + ".git", + ".tox", + "build", + ".mypy_cache", +] + +# Coverage configuration +# ---------------------- +[tool.coverage.run] +source = [ + "logki", +] + +# Formatting configuration +# ---------------------- +[tool.black] +target-version = [ + "py39", + "py310", + "py311" +] +line-length = 100 \ No newline at end of file diff --git a/tests/test_logki.py b/tests/test_logki.py new file mode 100755 index 0000000..1807e10 --- /dev/null +++ b/tests/test_logki.py @@ -0,0 +1,23 @@ +"""Basic tests for logki""" + +# Standard Imports +import os + +# Third-Party Imports +from prompt_toolkit.input import create_pipe_input +from prompt_toolkit.output import DummyOutput + +# Logki imports +import logki.logki as logki + + +def test_app(): + with create_pipe_input() as pipe_input: + pipe_input.send_text('q\n') + with logki.BufferedLog(os.path.join(os.path.dirname(__file__), "workloads", "example.log")) as buffered_log: + app = logki.create_app(buffered_log) + app.input = pipe_input + app.output = DummyOutput() + + # Run the application + app.run() diff --git a/tests/workloads/example.log b/tests/workloads/example.log new file mode 100755 index 0000000..57d4bf9 --- /dev/null +++ b/tests/workloads/example.log @@ -0,0 +1,222 @@ +449651305717147:(21845:21845)(kfree):call +449651305724100:(21845:21845)(kfree):return +449651305725579:(21845:21845)(kfree):call +449651305727153:(21845:21845)(__kmem_cache_free):call +449651305728525:(21845:21845)(__kmem_cache_free):return +449651305800008:(21845:21845)(kfree):return +449651305812030:(21845:21845)(kmem_cache_free):call +449651305821701:(21845:21845)(kmem_cache_free):return +449651305830381:(21845:21845)(syscall_exit_to_user_mode_prepare):call +449651305839140:(21845:21845)(syscall_exit_work):call +449651305849913:(21845:21845)(__audit_syscall_exit):call +449651305852432:(21845:21845)(__audit_syscall_exit):return +449651305854838:(21845:21845)(syscall_exit_work):return +449651305857253:(21845:21845)(syscall_exit_to_user_mode_prepare):return +449651305860482:(21845:21845)(exit_to_user_mode_prepare):call +449651305863155:(21845:21845)(_raw_spin_lock_irq):call +449651305865704:(21845:21845)(_raw_spin_lock_irq):return +449651305867916:(21845:21845)(_raw_spin_unlock_irq):call +449651305870599:(21845:21845)(_raw_spin_unlock_irq):return +449651305874335:(21845:21845)(__fput):call +449651305877772:(21845:21845)(__cond_resched):call +449651305879997:(21845:21845)(__cond_resched):return +449651305883346:(21845:21845)(mutex_lock):call +449651305884906:(21845:21845)(__cond_resched):call +449651305886964:(21845:21845)(__cond_resched):return +449651305889290:(21845:21845)(mutex_lock):return +449651305891884:(21845:21845)(_raw_spin_lock_irqsave):call +449651305893291:(21845:21845)(_raw_spin_lock_irqsave):return +449651305896600:(21845:21845)(_raw_spin_lock_irqsave):call +449651305897845:(21845:21845)(_raw_spin_lock_irqsave):return +449651305904870:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305907734:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305910259:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305915942:(21845:21845)(irq_enter_rcu):call +449651305921833:(21845:21845)(irqtime_account_irq):call +449651305925693:(21845:21845)(irqtime_account_irq):return +449651305929083:(21845:21845)(irq_enter_rcu):return +449651305936148:(21845:21845)(_raw_spin_lock_irqsave):call +449651305940816:(21845:21845)(_raw_spin_lock_irqsave):return +449651305947899:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305950353:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305952634:(21845:21845)(irq_exit_rcu):call +449651305955607:(21845:21845)(irqtime_account_irq):call +449651305958536:(21845:21845)(irqtime_account_irq):return +449651305960003:(21845:21845)(idle_cpu):call +449651305961408:(21845:21845)(idle_cpu):return +449651305962940:(21845:21845)(irq_exit_rcu):return +449651305964981:(21845:21845)(irq_enter_rcu):call +449651305966218:(21845:21845)(irqtime_account_irq):call +449651305967360:(21845:21845)(irqtime_account_irq):return +449651305968847:(21845:21845)(irq_enter_rcu):return +449651305970808:(21845:21845)(_raw_spin_lock_irqsave):call +449651305972420:(21845:21845)(_raw_spin_lock_irqsave):return +449651305974211:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305976131:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305978135:(21845:21845)(irq_exit_rcu):call +449651305979253:(21845:21845)(irqtime_account_irq):call +449651305981001:(21845:21845)(irqtime_account_irq):return +449651305982200:(21845:21845)(idle_cpu):call +449651305983705:(21845:21845)(idle_cpu):return +449651305984769:(21845:21845)(irq_exit_rcu):return +449651305986522:(21845:21845)(irq_enter_rcu):call +449651305988310:(21845:21845)(irqtime_account_irq):call +449651305990191:(21845:21845)(irqtime_account_irq):return +449651305991169:(21845:21845)(irq_enter_rcu):return +449651305992998:(21845:21845)(_raw_spin_lock_irqsave):call +449651305994149:(21845:21845)(_raw_spin_lock_irqsave):return +449651305995996:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651305997094:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651305999290:(21845:21845)(irq_exit_rcu):call +449651306000856:(21845:21845)(irqtime_account_irq):call +449651306002263:(21845:21845)(irqtime_account_irq):return +449651306003488:(21845:21845)(idle_cpu):call +449651306004589:(21845:21845)(idle_cpu):return +449651306005970:(21845:21845)(irq_exit_rcu):return +449651306007730:(21845:21845)(irq_enter_rcu):call +449651306008978:(21845:21845)(irqtime_account_irq):call +449651306010408:(21845:21845)(irqtime_account_irq):return +449651306011786:(21845:21845)(irq_enter_rcu):return +449651306013923:(21845:21845)(_raw_spin_lock_irqsave):call +449651306015042:(21845:21845)(_raw_spin_lock_irqsave):return +449651306017104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306018366:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306020129:(21845:21845)(irq_exit_rcu):call +449651306021165:(21845:21845)(irqtime_account_irq):call +449651306022889:(21845:21845)(irqtime_account_irq):return +449651306024142:(21845:21845)(idle_cpu):call +449651306025704:(21845:21845)(idle_cpu):return +449651306026937:(21845:21845)(irq_exit_rcu):return +449651306028874:(21845:21845)(irq_enter_rcu):call +449651306030361:(21845:21845)(irqtime_account_irq):call +449651306032054:(21845:21845)(irqtime_account_irq):return +449651306033084:(21845:21845)(irq_enter_rcu):return +449651306035164:(21845:21845)(_raw_spin_lock_irqsave):call +449651306036445:(21845:21845)(_raw_spin_lock_irqsave):return +449651306038223:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306039225:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306040914:(21845:21845)(irq_exit_rcu):call +449651306042387:(21845:21845)(irqtime_account_irq):call +449651306043823:(21845:21845)(irqtime_account_irq):return +449651306045094:(21845:21845)(idle_cpu):call +449651306046799:(21845:21845)(idle_cpu):return +449651306048282:(21845:21845)(irq_exit_rcu):return +449651306049905:(21845:21845)(irq_enter_rcu):call +449651306051063:(21845:21845)(irqtime_account_irq):call +449651306052677:(21845:21845)(irqtime_account_irq):return +449651306054156:(21845:21845)(irq_enter_rcu):return +449651306056001:(21845:21845)(_raw_spin_lock_irqsave):call +449651306057348:(21845:21845)(_raw_spin_lock_irqsave):return +449651306058914:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306060465:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306061750:(21845:21845)(irq_exit_rcu):call +449651306063251:(21845:21845)(irqtime_account_irq):call +449651306064998:(21845:21845)(irqtime_account_irq):return +449651306066683:(21845:21845)(idle_cpu):call +449651306067866:(21845:21845)(idle_cpu):return +449651306068994:(21845:21845)(irq_exit_rcu):return +449651306070886:(21845:21845)(irq_enter_rcu):call +449651306072286:(21845:21845)(irqtime_account_irq):call +449651306073883:(21845:21845)(irqtime_account_irq):return +449651306075087:(21845:21845)(irq_enter_rcu):return +449651306077129:(21845:21845)(_raw_spin_lock_irqsave):call +449651306078428:(21845:21845)(_raw_spin_lock_irqsave):return +449651306080104:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306081289:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306082424:(21845:21845)(irq_exit_rcu):call +449651306084461:(21845:21845)(irqtime_account_irq):call +449651306085655:(21845:21845)(irqtime_account_irq):return +449651306087347:(21845:21845)(idle_cpu):call +449651306088245:(21845:21845)(idle_cpu):return +449651306089812:(21845:21845)(irq_exit_rcu):return +449651306091789:(21845:21845)(irq_enter_rcu):call +449651306093231:(21845:21845)(irqtime_account_irq):call +449651306094161:(21845:21845)(irqtime_account_irq):return +449651306095499:(21845:21845)(irq_enter_rcu):return +449651306097027:(21845:21845)(_raw_spin_lock_irqsave):call +449651306098434:(21845:21845)(_raw_spin_lock_irqsave):return +449651306100032:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306101322:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306103370:(21845:21845)(irq_exit_rcu):call +449651306105076:(21845:21845)(irqtime_account_irq):call +449651306106109:(21845:21845)(irqtime_account_irq):return +449651306107586:(21845:21845)(idle_cpu):call +449651306108988:(21845:21845)(idle_cpu):return +449651306110299:(21845:21845)(irq_exit_rcu):return +449651306112028:(21845:21845)(irq_enter_rcu):call +449651306113911:(21845:21845)(irqtime_account_irq):call +449651306115148:(21845:21845)(irqtime_account_irq):return +449651306116955:(21845:21845)(irq_enter_rcu):return +449651306118563:(21845:21845)(_raw_spin_lock_irqsave):call +449651306120193:(21845:21845)(_raw_spin_lock_irqsave):return +449651306121698:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306123240:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306124573:(21845:21845)(irq_exit_rcu):call +449651306126425:(21845:21845)(irqtime_account_irq):call +449651306128107:(21845:21845)(irqtime_account_irq):return +449651306129739:(21845:21845)(idle_cpu):call +449651306131113:(21845:21845)(idle_cpu):return +449651306132204:(21845:21845)(irq_exit_rcu):return +449651306134263:(21845:21845)(irq_enter_rcu):call +449651306135755:(21845:21845)(irqtime_account_irq):call +449651306137490:(21845:21845)(irqtime_account_irq):return +449651306138257:(21845:21845)(irq_enter_rcu):return +449651306139967:(21845:21845)(_raw_spin_lock_irqsave):call +449651306141326:(21845:21845)(_raw_spin_lock_irqsave):return +449651306142941:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306143993:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306146020:(21845:21845)(irq_exit_rcu):call +449651306147271:(21845:21845)(irqtime_account_irq):call +449651306149021:(21845:21845)(irqtime_account_irq):return +449651306150343:(21845:21845)(idle_cpu):call +449651306151936:(21845:21845)(idle_cpu):return +449651306153351:(21845:21845)(irq_exit_rcu):return +449651306155400:(21845:21845)(irq_enter_rcu):call +449651306156749:(21845:21845)(irqtime_account_irq):call +449651306158440:(21845:21845)(irqtime_account_irq):return +449651306159673:(21845:21845)(irq_enter_rcu):return +449651306160914:(21845:21845)(_raw_spin_lock_irqsave):call +449651306161783:(21845:21845)(_raw_spin_lock_irqsave):return +449651306163150:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306164098:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306165525:(21845:21845)(irq_exit_rcu):call +449651306166404:(21845:21845)(irqtime_account_irq):call +449651306167628:(21845:21845)(irqtime_account_irq):return +449651306169374:(21845:21845)(idle_cpu):call +449651306170457:(21845:21845)(idle_cpu):return +449651306171490:(21845:21845)(irq_exit_rcu):return +449651306172920:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306174229:(21845:21845)(_raw_spin_lock_irqsave):call +449651306175561:(21845:21845)(_raw_spin_lock_irqsave):return +449651306176842:(21845:21845)(_raw_spin_unlock_irqrestore):call +449651306177852:(21845:21845)(_raw_spin_unlock_irqrestore):return +449651306179116:(21845:21845)(mutex_unlock):call +449651306180884:(21845:21845)(mutex_unlock):return +449651306184624:(21845:21845)(_raw_spin_lock):call +449651306186282:(21845:21845)(_raw_spin_lock):return +449651306188480:(21845:21845)(_raw_spin_unlock):call +449651306189664:(21845:21845)(_raw_spin_unlock):return +449651306192308:(21845:21845)(dput):call +449651306194809:(21845:21845)(__cond_resched):call +449651306196639:(21845:21845)(__cond_resched):return +449651306198886:(21845:21845)(dput):return +449651306201957:(21845:21845)(mntput):call +449651306203024:(21845:21845)(mntput):return +449651306204139:(21845:21845)(kmem_cache_free):call +449651306205971:(21845:21845)(__slab_free):call +449651306208669:(21845:21845)(__slab_free):return +449651306210733:(21845:21845)(kmem_cache_free):return +449651306212495:(21845:21845)(__call_rcu_common.constprop.0):call +449651306214769:(21845:21845)(rcu_nocb_try_bypass):call +449651306217920:(21845:21845)(rcu_segcblist_pend_cbs):call +449651306219060:(21845:21845)(rcu_segcblist_pend_cbs):return +449651306220460:(21845:21845)(rcu_nocb_try_bypass):return +449651306224060:(21845:21845)(rcu_segcblist_enqueue):call +449651306226501:(21845:21845)(rcu_segcblist_enqueue):return +449651306228010:(21845:21845)(__call_rcu_common.constprop.0):return +449651306229147:(21845:21845)(__fput):return +449651306232040:(21845:21845)(__cond_resched):call +449651306235163:(21845:21845)(__cond_resched):return +449651306238018:(21845:21845)(mem_cgroup_handle_over_high):call +449651306240262:(21845:21845)(mem_cgroup_handle_over_high):return +449651306242616:(21845:21845)(exit_to_user_mode_prepare):return diff --git a/tox.ini b/tox.ini new file mode 100755 index 0000000..6393f28 --- /dev/null +++ b/tox.ini @@ -0,0 +1,41 @@ +[tox] +requires = + tox>=4 +env_list = + py{3.9, 3.10, 3.11} + lint + typing + docs + +[testenv] +description = Run logki tests +usedevelop=True +allowlist_externals = make +extras = test +commands = + make test-ci + +[testenv:lint] +description = Run code style checker Pylint +allowlist_externals = make +extras = lint +commands = + make lint + +[testenv:typing] +# We can't skip install as some of our dependencies ship type hints directly in their core package +# and not as a standalone typeshed package. +description = Run static type checker Mypy +allowlist_externals = make +extras = typing +commands = + make check + +[testenv:docs] +description = Generate Sphinx HTML documentation +allowlist_externals = make +extras = docs +commands = + make docs +[pytest] +norecursedirs = docs *.egg-info .git .tox build .mypy_cache From 24063ecb74505b08d360f64eecca2c6283fbdf13 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 10:11:44 +0200 Subject: [PATCH 2/8] Fix tox error --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index eccb5b9..0f0a4a9 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,9 @@ requires = [ ] build-backend = "setuptools.build_meta" +[tool.setuptools] +py-modules = ['logki'] + [project] name = "logki" description = "logki: Log Analysis Kit" From 85d3a5e0b15dd84501760f5448c0ec1d7be07412 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 10:34:30 +0200 Subject: [PATCH 3/8] Fix typing --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0f0a4a9..a0dc534 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,9 +60,6 @@ logki = "logki.logki:launch" # Mypy configuration # ---------------------- [tool.mypy] -plugins = [ - "numpy.typing.mypy_plugin" -] exclude = [ ".git", ".mypy_cache", From 3eebe93b6ee78c5ef7009ad1f9f3e396cb1698fd Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 10:56:19 +0200 Subject: [PATCH 4/8] Fix bad package --- logki/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 logki/__init__.py diff --git a/logki/__init__.py b/logki/__init__.py new file mode 100755 index 0000000..cf1690e --- /dev/null +++ b/logki/__init__.py @@ -0,0 +1,6 @@ +"""logki is a log analysis kit""" +from __future__ import annotations + +import importlib.metadata + +__version__ = importlib.metadata.version("logki") \ No newline at end of file From 5c73e56894bd31691d3e00faf0cc90a87e371bc8 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 11:00:09 +0200 Subject: [PATCH 5/8] Rename module --- logki/{logki.py => app.py} | 0 pyproject.toml | 2 +- tests/test_logki.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename logki/{logki.py => app.py} (100%) diff --git a/logki/logki.py b/logki/app.py similarity index 100% rename from logki/logki.py rename to logki/app.py diff --git a/pyproject.toml b/pyproject.toml index a0dc534..5d74239 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ Repository = "https://github.com/Perfexionists/logki.git" Changelog = "https://github.com/Perfexionists/logki/blob/master/CHANGELOG.rst" [project.scripts] -logki = "logki.logki:launch" +logki = "logki.app:launch" # Mypy configuration # ---------------------- diff --git a/tests/test_logki.py b/tests/test_logki.py index 1807e10..155c217 100755 --- a/tests/test_logki.py +++ b/tests/test_logki.py @@ -8,7 +8,7 @@ from prompt_toolkit.output import DummyOutput # Logki imports -import logki.logki as logki +import logki.app as logki def test_app(): From f82f844a5e8284ed2d7221017fc477ddafbc5fd3 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 11:27:48 +0200 Subject: [PATCH 6/8] Fix packaging --- .github/workflows/release.yml | 2 +- pyproject.toml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d345dd3..cc9106b 100755 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Install logki(to assure it is correctly installed) and try obtaining the version + - name: Install logki (to assure it is correctly installed) and try obtaining the version run: | make install logki --version diff --git a/pyproject.toml b/pyproject.toml index 5d74239..010b6a8 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,19 @@ build-backend = "setuptools.build_meta" [tool.setuptools] py-modules = ['logki'] +package-dir = {'logki' = 'logki'} + +[tool.setuptools.packages.find] +where = ['.'] +include = [ + 'logki', + 'logki*' +] +namespaces = true + +[tool.setuptools.package-data] +logki = [ +] [project] name = "logki" From 1819ae7cef61b3a7f31b1b612b60cc02c6eaf6b2 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 12:40:15 +0200 Subject: [PATCH 7/8] Fix minor issues --- logki/app.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/logki/app.py b/logki/app.py index 82c2eae..1367550 100755 --- a/logki/app.py +++ b/logki/app.py @@ -401,14 +401,16 @@ def process_command(buff): def launch(): """Launches logki""" - if len(sys.argv) != 2: + if len(sys.argv) == 2 and sys.argv[1] == '--version': + print(__VERSION__) + sys.exit(0) + elif len(sys.argv) == 2: + with BufferedLog(sys.argv[1]) as buffered_log: + application = create_app(buffered_log) + application.run() + else: print("usage: ./logki.py .log") sys.exit(1) - elif len(sys.argv) == 1 and sys.argv[1] == '--version': - print(__VERSION__) - with BufferedLog(sys.argv[1]) as buffered_log: - application = create_app(buffered_log) - application.run() if __name__ == "__main__": From 4461a8f0dc0cab884f9883122de272a2af6bd6f0 Mon Sep 17 00:00:00 2001 From: Tomas Fiedor Date: Sat, 20 Apr 2024 13:33:51 +0200 Subject: [PATCH 8/8] Add typing --- logki/app.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/logki/app.py b/logki/app.py index 1367550..3279a39 100755 --- a/logki/app.py +++ b/logki/app.py @@ -2,7 +2,7 @@ from __future__ import annotations # Standard Imports -from typing import Optional, TextIO +from typing import Optional, TextIO, Any from dataclasses import dataclass import io import sys @@ -58,6 +58,7 @@ def __enter__(self) -> BufferedLog: def __exit__(self, exc_type: type, exc_val: Exception, exc_tb: BaseException) -> None: """Closes the file""" + assert self.file is not None self.file.close() def read_next_line(self) -> str: @@ -65,6 +66,7 @@ def read_next_line(self) -> str: :return: next line in the buffer """ + assert self.file is not None if self.current_position >= self.end_position: return "" self.file.seek(self.current_position) @@ -77,6 +79,7 @@ def read_previous_line(self) -> str: :return: previous line in the buffer """ + assert self.file is not None block = "" while self.current_position > 0: to_read = min(self.block_size, self.current_position) @@ -98,6 +101,7 @@ def read_previous_line(self) -> str: def get_current_position(self) -> int: """Returns the current position in the log """ + assert self.file is not None return self.file.tell() def move_current_position(self, position: int) -> None: @@ -105,11 +109,13 @@ def move_current_position(self, position: int) -> None: :param position: new position in the log """ + assert self.file is not None self.current_position = position self.file.seek(position) def close(self): """Closes the buffered log""" + assert self.file is not None self.file.close() @@ -168,14 +174,14 @@ class State: :ivar first_timestamp: first timestamp in the log :ivar stack: stack of the calls """ - def __init__(self): + def __init__(self) -> None: self.current_line: int = 0 # Tracks the currently highlighted line self.real_line: int = 0 self.buffered_log: Optional[BufferedLog] = None - self.last_command = "" - self.current_timestamp = 0 - self.first_timestamp = 0 - self.stack = [] + self.last_command: str = "" + self.current_timestamp: int = 0 + self.first_timestamp : int= 0 + self.stack: list[str] = [] self._log_content: list[str] = [] self._buffer_positions: list[int] = [] @@ -187,12 +193,12 @@ def get_content(self) -> list[str]: """Returns current content of the log""" return self._log_content - def init_buffer(self, buffered_log: BufferedLog): + def init_buffer(self, buffered_log: BufferedLog) -> None: """Initializes the buffer from buffered log. :param buffered_log: buffered log """ - self.buffered_log: BufferedLog = buffered_log + self.buffered_log = buffered_log self._buffer_log_start = 0 for i in range(0, self._buffer_size): self._log_content.append(self.buffered_log.read_next_line()) @@ -203,6 +209,7 @@ def init_buffer(self, buffered_log: BufferedLog): def move_window_forward(self) -> None: """Moves window forward by one line""" + assert self.buffered_log is not None self.real_line += 1 if self.current_line <= (self._buffer_size - 6): self.current_line = min(self.current_line + 1, self._buffer_size) @@ -219,6 +226,7 @@ def move_window_forward(self) -> None: def move_window_backward(self) -> None: """Moves window back by one line""" + assert self.buffered_log is not None self.real_line = max(self.real_line - 1, 0) if self.current_line > 5 or self.real_line <= 5: self.current_line = max(self.current_line - 1, 0) @@ -327,7 +335,7 @@ def get_stack() -> list[tuple[str, str]]: return lines -def create_app(buffered_log: BufferedLog) -> Application: +def create_app(buffered_log: BufferedLog) -> Application[Any]: """Creates apllication for given buffered log :param buffered_log: buffered log @@ -393,7 +401,7 @@ def process_command(buff): ) # Create the application - app = Application( + app: Application[Any] = Application( layout=Layout(root_container), key_bindings=bindings, style=style, full_screen=True ) return app